Merge "Clean up Outline API, method on drawable"
diff --git a/api/current.txt b/api/current.txt
index 5b36763..6353ada 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -864,6 +864,7 @@
     field public static final int paddingBottom = 16842969; // 0x10100d9
     field public static final int paddingEnd = 16843700; // 0x10103b4
     field public static final int paddingLeft = 16842966; // 0x10100d6
+    field public static final int paddingMode = 16843866; // 0x101045a
     field public static final int paddingRight = 16842968; // 0x10100d8
     field public static final int paddingStart = 16843699; // 0x10103b3
     field public static final int paddingTop = 16842967; // 0x10100d7
@@ -1640,7 +1641,6 @@
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
     field public static final int selectedIcon = 16908302; // 0x102000e
-    field public static final int shared_element = 16908354; // 0x1020042
     field public static final int startSelectingText = 16908328; // 0x1020028
     field public static final int stopSelectingText = 16908329; // 0x1020029
     field public static final int summary = 16908304; // 0x1020010
@@ -2830,6 +2830,12 @@
     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
   }
 
+  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
+    ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
+    method public abstract T convertBack(V);
+    method public android.animation.BidirectionalTypeConverter<V, T> invert();
+  }
+
   public class FloatArrayEvaluator implements android.animation.TypeEvaluator {
     ctor public FloatArrayEvaluator();
     ctor public FloatArrayEvaluator(float[]);
@@ -3008,7 +3014,6 @@
   public abstract class TypeConverter {
     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract V convert(T);
-    method public T convertBack(V);
   }
 
   public abstract interface TypeEvaluator {
@@ -3336,6 +3341,8 @@
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
+    method public void setEnterSharedElementListener(android.app.SharedElementListener);
+    method public void setExitSharedElementListener(android.app.SharedElementListener);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
     method public final void setFeatureDrawableResource(int, int);
@@ -3351,7 +3358,6 @@
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
     method public final void setSecondaryProgress(int);
-    method public void setSharedElementListener(android.app.SharedElementListener);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
@@ -4418,6 +4424,8 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public java.lang.String getGroup();
+    method public java.lang.String getSortKey();
     method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4460,6 +4468,7 @@
     field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
     field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
     field public static final int FLAG_INSISTENT = 4; // 0x4
     field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
@@ -4510,6 +4519,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput[] getRemoteInputs();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public android.app.PendingIntent actionIntent;
@@ -4517,14 +4527,20 @@
     field public java.lang.CharSequence title;
   }
 
-  public static class Notification.Action.Builder {
+  public static final class Notification.Action.Builder {
     ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
     ctor public Notification.Action.Builder(android.app.Notification.Action);
     method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
+    method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
+    method public android.app.Notification.Action.Builder apply(android.app.Notification.Action.Builder.Extender);
     method public android.app.Notification.Action build();
     method public android.os.Bundle getExtras();
   }
 
+  public static abstract interface Notification.Action.Builder.Extender {
+    method public abstract android.app.Notification.Action.Builder applyTo(android.app.Notification.Action.Builder);
+  }
+
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
     ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
@@ -4548,6 +4564,7 @@
     method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
+    method public android.app.Notification.Builder apply(android.app.Notification.Builder.Extender);
     method public android.app.Notification build();
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
@@ -4563,6 +4580,8 @@
     method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setExtras(android.os.Bundle);
     method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+    method public android.app.Notification.Builder setGroup(java.lang.String);
+    method public android.app.Notification.Builder setGroupSummary(boolean);
     method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.Builder setLights(int, int, int);
     method public android.app.Notification.Builder setLocalOnly(boolean);
@@ -4575,6 +4594,7 @@
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
+    method public android.app.Notification.Builder setSortKey(java.lang.String);
     method public android.app.Notification.Builder setSound(android.net.Uri);
     method public android.app.Notification.Builder setSound(android.net.Uri, int);
     method public android.app.Notification.Builder setStyle(android.app.Notification.Style);
@@ -4587,6 +4607,10 @@
     method public android.app.Notification.Builder setWhen(long);
   }
 
+  public static abstract interface Notification.Builder.Extender {
+    method public abstract android.app.Notification.Builder applyTo(android.app.Notification.Builder);
+  }
+
   public static class Notification.InboxStyle extends android.app.Notification.Style {
     ctor public Notification.InboxStyle();
     ctor public Notification.InboxStyle(android.app.Notification.Builder);
@@ -4690,6 +4714,31 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RemoteInput implements android.os.Parcelable {
+    method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
+    method public int describeContents();
+    method public boolean getAllowFreeFormInput();
+    method public java.lang.CharSequence[] getChoices();
+    method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getResultKey();
+    method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(java.lang.String);
+    method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public android.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
+    method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+  }
+
   public class SearchManager implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
     method public android.content.ComponentName getGlobalSearchActivity();
     method public android.app.SearchableInfo getSearchableInfo(android.content.ComponentName);
@@ -4810,7 +4859,7 @@
     field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
   }
 
-  public class SharedElementListener {
+  public abstract class SharedElementListener {
     ctor public SharedElementListener();
     method public void handleRejectedSharedElements(java.util.List<android.view.View>);
     method public void remapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
@@ -5047,6 +5096,7 @@
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(android.content.ComponentName);
     method public boolean isProfileOwnerApp(java.lang.String);
@@ -5054,8 +5104,11 @@
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setApplicationBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
+    method public int setApplicationsBlocked(android.content.ComponentName, android.content.Intent, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
+    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
@@ -5071,6 +5124,7 @@
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
     method public void setProfileEnabled(android.content.ComponentName);
+    method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -5364,6 +5418,8 @@
     method public boolean disable();
     method public boolean enable();
     method public java.lang.String getAddress();
+    method public android.bluetooth.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
+    method public android.bluetooth.BluetoothLeScanner getBluetoothLeScanner();
     method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public java.lang.String getName();
@@ -6006,6 +6062,178 @@
     method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
   }
 
+  public final class BluetoothLeAdvertiseScanData {
+    ctor public BluetoothLeAdvertiseScanData();
+    field public static final int ADVERTISING_DATA = 0; // 0x0
+    field public static final int PARSED_SCAN_RECORD = 2; // 0x2
+  }
+
+  public static abstract class BluetoothLeAdvertiseScanData.AdvertiseBaseData {
+    method public int getDataType();
+    method public int getManufacturerId();
+    method public byte[] getManufacturerSpecificData();
+    method public byte[] getServiceData();
+    method public android.os.ParcelUuid getServiceDataUuid();
+    method public java.util.List<android.os.ParcelUuid> getServiceUuids();
+  }
+
+  public static final class BluetoothLeAdvertiseScanData.AdvertisementData extends android.bluetooth.BluetoothLeAdvertiseScanData.AdvertiseBaseData implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean getIncludeTxPowerLevel();
+    method public static android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder newBuilder();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class BluetoothLeAdvertiseScanData.AdvertisementData.Builder {
+    ctor public BluetoothLeAdvertiseScanData.AdvertisementData.Builder();
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData build();
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder dataType(int);
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder includeTxPowerLevel(boolean);
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder manufacturerData(int, byte[]);
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder serviceData(android.os.ParcelUuid, byte[]);
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData.Builder serviceUuids(java.util.List<android.os.ParcelUuid>);
+  }
+
+  public static final class BluetoothLeAdvertiseScanData.ScanRecord extends android.bluetooth.BluetoothLeAdvertiseScanData.AdvertiseBaseData {
+    method public int getAdvertiseFlags();
+    method public java.lang.String getLocalName();
+    method public static android.bluetooth.BluetoothLeAdvertiseScanData.ScanRecord.Parser getParser();
+    method public int getTxPowerLevel();
+  }
+
+  public static final class BluetoothLeAdvertiseScanData.ScanRecord.Parser {
+    ctor public BluetoothLeAdvertiseScanData.ScanRecord.Parser();
+    method public android.bluetooth.BluetoothLeAdvertiseScanData.ScanRecord parseFromScanRecord(byte[]);
+  }
+
+  public class BluetoothLeAdvertiser {
+    method public void startAdvertising(android.bluetooth.BluetoothLeAdvertiser.Settings, android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData, android.bluetooth.BluetoothLeAdvertiser.AdvertiseCallback);
+    method public void stopAdvertising(android.bluetooth.BluetoothLeAdvertiser.Settings, android.bluetooth.BluetoothLeAdvertiser.AdvertiseCallback);
+  }
+
+  public static abstract interface BluetoothLeAdvertiser.AdvertiseCallback {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess(android.bluetooth.BluetoothLeAdvertiser.Settings);
+    field public static final int ADVERISING_NOT_STARTED = 4; // 0x4
+    field public static final int ADVERTISING_ALREADY_STARTED = 3; // 0x3
+    field public static final int ADVERTISING_SERVICE_UNKNOWN = 1; // 0x1
+    field public static final int CONTROLLER_FAILURE = 5; // 0x5
+    field public static final int TOO_MANY_ADVERTISERS = 2; // 0x2
+  }
+
+  public static final class BluetoothLeAdvertiser.Settings implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getMode();
+    method public int getTxPowerLevel();
+    method public int getType();
+    method public static android.bluetooth.BluetoothLeAdvertiser.Settings.Builder newBuilder();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ADVERTISE_MODE_BALANCED = 1; // 0x1
+    field public static final int ADVERTISE_MODE_LOW_LATENCY = 2; // 0x2
+    field public static final int ADVERTISE_MODE_LOW_POWER = 0; // 0x0
+    field public static final int ADVERTISE_TX_POWER_HIGH = 3; // 0x3
+    field public static final int ADVERTISE_TX_POWER_LOW = 1; // 0x1
+    field public static final int ADVERTISE_TX_POWER_MEDIUM = 2; // 0x2
+    field public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0; // 0x0
+    field public static final int ADVERTISE_TYPE_CONNECTABLE = 2; // 0x2
+    field public static final int ADVERTISE_TYPE_NON_CONNECTABLE = 0; // 0x0
+    field public static final int ADVERTISE_TYPE_SCANNABLE = 1; // 0x1
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class BluetoothLeAdvertiser.Settings.Builder {
+    method public android.bluetooth.BluetoothLeAdvertiser.Settings.Builder advertiseMode(int);
+    method public android.bluetooth.BluetoothLeAdvertiser.Settings build();
+    method public android.bluetooth.BluetoothLeAdvertiser.Settings.Builder txPowerLevel(int);
+    method public android.bluetooth.BluetoothLeAdvertiser.Settings.Builder type(int);
+  }
+
+  public final class BluetoothLeScanFilter implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getDeviceAddress();
+    method public java.lang.String getLocalName();
+    method public byte[] getManufacturerData();
+    method public byte[] getManufacturerDataMask();
+    method public int getManufacturerId();
+    method public int getMaxRssi();
+    method public int getMinRssi();
+    method public byte[] getServiceData();
+    method public byte[] getServiceDataMask();
+    method public android.os.ParcelUuid getServiceUuid();
+    method public android.os.ParcelUuid getServiceUuidMask();
+    method public boolean matches(android.bluetooth.BluetoothLeScanner.ScanResult);
+    method public static android.bluetooth.BluetoothLeScanFilter.Builder newBuilder();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static class BluetoothLeScanFilter.Builder {
+    method public android.bluetooth.BluetoothLeScanFilter build();
+    method public android.bluetooth.BluetoothLeScanFilter.Builder macAddress(java.lang.String);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder manufacturerData(int, byte[]);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder manufacturerDataMask(byte[]);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder name(java.lang.String);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder rssiRange(int, int);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder serviceData(byte[]);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder serviceDataMask(byte[]);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder serviceUuid(android.os.ParcelUuid);
+    method public android.bluetooth.BluetoothLeScanFilter.Builder serviceUuidMask(android.os.ParcelUuid);
+  }
+
+  public class BluetoothLeScanner {
+    method public void startScan(java.util.List<android.bluetooth.BluetoothLeScanFilter>, android.bluetooth.BluetoothLeScanner.Settings, android.bluetooth.BluetoothLeScanner.ScanCallback);
+    method public void stopScan(android.bluetooth.BluetoothLeScanner.Settings);
+  }
+
+  public static abstract interface BluetoothLeScanner.ScanCallback {
+    method public abstract void onBatchScanResults(java.util.List<android.bluetooth.BluetoothLeScanner.ScanResult>);
+    method public abstract void onDeviceFound(android.bluetooth.BluetoothLeScanner.ScanResult);
+    method public abstract void onDeviceLost(android.bluetooth.BluetoothDevice);
+    method public abstract void onDeviceUpdate(android.bluetooth.BluetoothLeScanner.ScanResult);
+    method public abstract void onScanFailed(int);
+    field public static final int APPLICATION_REGISTRATION_FAILED = 2; // 0x2
+    field public static final int CONTROLLER_FAILURE = 4; // 0x4
+    field public static final int GATT_SERVICE_FAILURE = 3; // 0x3
+    field public static final int SCAN_ALREADY_STARTED = 1; // 0x1
+  }
+
+  public static final class BluetoothLeScanner.ScanResult implements android.os.Parcelable {
+    ctor public BluetoothLeScanner.ScanResult(android.bluetooth.BluetoothDevice, byte[], int, long);
+    method public int describeContents();
+    method public android.bluetooth.BluetoothDevice getDevice();
+    method public int getRssi();
+    method public byte[] getScanRecord();
+    method public long getTimestampMicros();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class BluetoothLeScanner.Settings implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCallbackType();
+    method public long getReportDelayMicros();
+    method public int getScanMode();
+    method public int getScanResultType();
+    method public static android.bluetooth.BluetoothLeScanner.Settings.Builder newBuilder();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CALLBACK_TYPE_ON_FOUND = 1; // 0x1
+    field public static final int CALLBACK_TYPE_ON_LOST = 2; // 0x2
+    field public static final int CALLBACK_TYPE_ON_UPDATE = 0; // 0x0
+    field public static final android.os.Parcelable.Creator CREATOR;
+    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_RESULT_TYPE_FULL = 0; // 0x0
+  }
+
+  public static class BluetoothLeScanner.Settings.Builder {
+    method public android.bluetooth.BluetoothLeScanner.Settings build();
+    method public android.bluetooth.BluetoothLeScanner.Settings.Builder callbackType(int);
+    method public android.bluetooth.BluetoothLeScanner.Settings.Builder reportDelayMicros(long);
+    method public android.bluetooth.BluetoothLeScanner.Settings.Builder scanMode(int);
+  }
+
   public final class BluetoothManager {
     method public android.bluetooth.BluetoothAdapter getAdapter();
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -8091,6 +8319,7 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
+    field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
@@ -12647,15 +12876,14 @@
 
   public class UsbConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public int getAttributes();
     method public int getId();
     method public android.hardware.usb.UsbInterface getInterface(int);
     method public int getInterfaceCount();
     method public int getMaxPower();
     method public java.lang.String getName();
+    method public boolean isRemoteWakeup();
+    method public boolean isSelfPowered();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ATTR_REMOTE_WAKEUP_MASK = 32; // 0x20
-    field public static final int ATTR_SELF_POWERED_MASK = 64; // 0x40
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
@@ -14756,6 +14984,7 @@
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
     method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+    method public android.media.session.MediaSession getMediaSession();
     method public void setMetadataUpdateListener(android.media.RemoteControlClient.OnMetadataUpdateListener);
     method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
     method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
@@ -20813,6 +21042,7 @@
     field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
+    field public static final java.lang.String DISALLOW_TELEPHONY = "no_telephony";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
     field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
@@ -23627,7 +23857,7 @@
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
-    field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String MODE_RINGER = "mode_ringer";
     field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
     field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
@@ -23697,7 +23927,7 @@
     field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
     field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
     field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
-    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String LOCATION_MODE = "location_mode";
     field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
     field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
@@ -25377,10 +25607,10 @@
   public class FingerprintManager {
     ctor public FingerprintManager(android.content.Context);
     method public void enroll(long);
+    method public boolean enrolledAndEnabled();
     method public void remove(int);
     method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
     method public void stopListening();
-    field protected static final boolean DEBUG = true;
     field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
     field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
     field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -25410,20 +25640,24 @@
     method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
+    method public java.lang.String[] getActiveNotificationKeys();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
-    method public java.lang.String[] getOrderedNotificationKeys();
+    method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onListenerConnected(java.lang.String[]);
-    method public void onNotificationOrderUpdate();
     method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
+    method public void onNotificationRankingUpdate();
     method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
   }
 
-  public class NotificationOrderUpdate implements android.os.Parcelable {
-    ctor public NotificationOrderUpdate(android.os.Parcel);
+  public static class NotificationListenerService.Ranking implements android.os.Parcelable {
     method public int describeContents();
+    method public int getIndexOfKey(java.lang.String);
+    method public java.lang.String[] getOrderedKeys();
+    method public boolean isAmbient(java.lang.String);
+    method public boolean isInterceptedByDoNotDisturb(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -30664,6 +30898,7 @@
     field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
     field public static final int SOURCE_DPAD = 513; // 0x201
     field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
     field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
     field public static final int SOURCE_KEYBOARD = 257; // 0x101
     field public static final int SOURCE_MOUSE = 8194; // 0x2002
@@ -30832,6 +31067,8 @@
     field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
     field public static final int KEYCODE_0 = 7; // 0x7
     field public static final int KEYCODE_1 = 8; // 0x8
+    field public static final int KEYCODE_11 = 227; // 0xe3
+    field public static final int KEYCODE_12 = 228; // 0xe4
     field public static final int KEYCODE_2 = 9; // 0x9
     field public static final int KEYCODE_3 = 10; // 0xa
     field public static final int KEYCODE_3D_MODE = 206; // 0xce
@@ -30951,6 +31188,7 @@
     field public static final int KEYCODE_KATAKANA_HIRAGANA = 215; // 0xd7
     field public static final int KEYCODE_L = 40; // 0x28
     field public static final int KEYCODE_LANGUAGE_SWITCH = 204; // 0xcc
+    field public static final int KEYCODE_LAST_CHANNEL = 229; // 0xe5
     field public static final int KEYCODE_LEFT_BRACKET = 71; // 0x47
     field public static final int KEYCODE_M = 41; // 0x29
     field public static final int KEYCODE_MANNER_MODE = 205; // 0xcd
@@ -30966,6 +31204,7 @@
     field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82
     field public static final int KEYCODE_MEDIA_REWIND = 89; // 0x59
     field public static final int KEYCODE_MEDIA_STOP = 86; // 0x56
+    field public static final int KEYCODE_MEDIA_TOP_MENU = 226; // 0xe2
     field public static final int KEYCODE_MENU = 82; // 0x52
     field public static final int KEYCODE_META_LEFT = 117; // 0x75
     field public static final int KEYCODE_META_RIGHT = 118; // 0x76
@@ -31038,6 +31277,7 @@
     field public static final int KEYCODE_T = 48; // 0x30
     field public static final int KEYCODE_TAB = 61; // 0x3d
     field public static final int KEYCODE_TV = 170; // 0xaa
+    field public static final int KEYCODE_TV_DATA_SERVICE = 230; // 0xe6
     field public static final int KEYCODE_TV_INPUT = 178; // 0xb2
     field public static final int KEYCODE_TV_POWER = 177; // 0xb1
     field public static final int KEYCODE_U = 49; // 0x31
diff --git a/core/java/android/animation/BidirectionalTypeConverter.java b/core/java/android/animation/BidirectionalTypeConverter.java
new file mode 100644
index 0000000..960650e
--- /dev/null
+++ b/core/java/android/animation/BidirectionalTypeConverter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+/**
+ * Abstract base class used convert type T to another type V and back again. This
+ * is necessary when the value types of in animation are different from the property
+ * type. BidirectionalTypeConverter is needed when only the final value for the
+ * animation is supplied to animators.
+ * @see PropertyValuesHolder#setConverter(TypeConverter)
+ */
+public abstract class BidirectionalTypeConverter<T, V> extends TypeConverter<T, V> {
+    private BidirectionalTypeConverter mInvertedConverter;
+
+    public BidirectionalTypeConverter(Class<T> fromClass, Class<V> toClass) {
+        super(fromClass, toClass);
+    }
+
+    /**
+     * Does a conversion from the target type back to the source type. The subclass
+     * must implement this when a TypeConverter is used in animations and current
+     * values will need to be read for an animation.
+     * @param value The Object to convert.
+     * @return A value of type T, converted from <code>value</code>.
+     */
+    public abstract T convertBack(V value);
+
+    /**
+     * Returns the inverse of this converter, where the from and to classes are reversed.
+     * The inverted converter uses this convert to call {@link #convertBack(Object)} for
+     * {@link #convert(Object)} calls and {@link #convert(Object)} for
+     * {@link #convertBack(Object)} calls.
+     * @return The inverse of this converter, where the from and to classes are reversed.
+     */
+    public BidirectionalTypeConverter<V, T> invert() {
+        if (mInvertedConverter == null) {
+            mInvertedConverter = new InvertedConverter(this);
+        }
+        return mInvertedConverter;
+    }
+
+    private static class InvertedConverter<From, To> extends BidirectionalTypeConverter<From, To> {
+        private BidirectionalTypeConverter<To, From> mConverter;
+
+        public InvertedConverter(BidirectionalTypeConverter<To, From> converter) {
+            super(converter.getTargetType(), converter.getSourceType());
+            mConverter = converter;
+        }
+
+        @Override
+        public From convertBack(To value) {
+            return mConverter.convert(value);
+        }
+
+        @Override
+        public To convert(From value) {
+            return mConverter.convertBack(value);
+        }
+    }
+}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index c0ce795..130754e 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -610,8 +610,8 @@
      * along the way, and an ending value (these values will be distributed evenly across
      * the duration of the animation). This variant supplies a <code>TypeConverter</code> to
      * convert from the animated values to the type of the property. If only one value is
-     * supplied, the <code>TypeConverter</code> must implement
-     * {@link TypeConverter#convertBack(Object)} to retrieve the current value.
+     * supplied, the <code>TypeConverter</code> must be a
+     * {@link android.animation.BidirectionalTypeConverter} to retrieve the current value.
      *
      * @param target The object whose property is to be animated.
      * @param property The property being animated.
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 8fce80a..bf2924c 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -456,7 +456,7 @@
      * cannot automatically interpolate between objects of unknown type. This variant also
      * takes a <code>TypeConverter</code> to convert from animated values to the type
      * of the property. If only one value is supplied, the <code>TypeConverter</code>
-     * must implement {@link TypeConverter#convertBack(Object)} to retrieve the current
+     * must be a {@link android.animation.BidirectionalTypeConverter} to retrieve the current
      * value.
      *
      * @param property The property being animated. Should not be null.
@@ -635,6 +635,8 @@
 
     /**
      * Sets the converter to convert from the values type to the setter's parameter type.
+     * If only one value is supplied, <var>converter</var> must be a
+     * {@link android.animation.BidirectionalTypeConverter}.
      * @param converter The converter to use to convert values.
      */
     public void setConverter(TypeConverter converter) {
@@ -816,12 +818,12 @@
 
     private Object convertBack(Object value) {
         if (mConverter != null) {
-            value = mConverter.convertBack(value);
-            if (value == null) {
+            if (!(mConverter instanceof BidirectionalTypeConverter)) {
                 throw new IllegalArgumentException("Converter "
                         + mConverter.getClass().getName()
-                        + " must implement convertBack and not return null.");
+                        + " must be a BidirectionalTypeConverter");
             }
+            value = ((BidirectionalTypeConverter) mConverter).convertBack(value);
         }
         return value;
     }
diff --git a/core/java/android/animation/TypeConverter.java b/core/java/android/animation/TypeConverter.java
index 03b3eb5..9ead2ad 100644
--- a/core/java/android/animation/TypeConverter.java
+++ b/core/java/android/animation/TypeConverter.java
@@ -53,16 +53,4 @@
      * @return A value of type V, converted from <code>value</code>.
      */
     public abstract V convert(T value);
-
-    /**
-     * Does a conversion from the target type back to the source type. The subclass
-     * must implement this when a TypeConverter is used in animations and current
-     * values will need to be read for an animation. By default, this will return null,
-     * indicating that back-conversion is not supported.
-     * @param value The Object to convert.
-     * @return A value of type T, converted from <code>value</code>.
-     */
-    public T convertBack(V value) {
-        return null;
-    }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e1a94d7..3de971c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -779,7 +779,8 @@
     final Handler mHandler = new Handler();
 
     private ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
-    SharedElementListener mTransitionListener = new SharedElementListener();
+    SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER;
+    SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER;
 
     /** Return the intent that started this activity. */
     public Intent getIntent() {
@@ -5557,16 +5558,32 @@
     /**
      * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
      * android.view.View, String)} was used to start an Activity, <var>listener</var>
-     * will be called to handle shared elements. This requires
+     * will be called to handle shared elements on the <i>launched</i> Activity. This requires
      * {@link Window#FEATURE_CONTENT_TRANSITIONS}.
      *
-     * @param listener Used to manipulate how shared element transitions function.
+     * @param listener Used to manipulate shared element transitions on the launched Activity.
      */
-    public void setSharedElementListener(SharedElementListener listener) {
+    public void setEnterSharedElementListener(SharedElementListener listener) {
         if (listener == null) {
-            listener = new SharedElementListener();
+            listener = SharedElementListener.NULL_LISTENER;
         }
-        mTransitionListener = listener;
+        mEnterTransitionListener = listener;
+    }
+
+    /**
+     * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+     * android.view.View, String)} was used to start an Activity, <var>listener</var>
+     * will be called to handle shared elements on the <i>launching</i> Activity. Most
+     * calls will only come when returning from the started Activity.
+     * This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+     *
+     * @param listener Used to manipulate shared element transitions on the launching Activity.
+     */
+    public void setExitSharedElementListener(SharedElementListener listener) {
+        if (listener == null) {
+            listener = SharedElementListener.NULL_LISTENER;
+        }
+        mExitTransitionListener = listener;
     }
 
     // ------------------ Internal API ------------------
@@ -5882,7 +5899,8 @@
      * have completed drawing. This is necessary only after an {@link Activity} has been made
      * opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn
      * translucent again following a call to {@link
-     * Activity#convertToTranslucent(TranslucentConversionListener)}.
+     * Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener,
+     * ActivityOptions)}
      *
      * @hide
      */
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 6c6a52f..2acf5b2 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -189,15 +189,17 @@
     final protected SharedElementListener mListener;
     protected ResultReceiver mResultReceiver;
     final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
+    final protected boolean mIsReturning;
 
     public ActivityTransitionCoordinator(Window window,
             ArrayList<String> allSharedElementNames,
             ArrayList<String> accepted, ArrayList<String> localNames,
-            SharedElementListener listener) {
+            SharedElementListener listener, boolean isReturning) {
         super(new Handler());
         mWindow = window;
         mListener = listener;
         mAllSharedElementNames = allSharedElementNames;
+        mIsReturning = isReturning;
         setSharedElements(accepted, localNames);
         if (getViewsTransition() != null) {
             getDecor().captureTransitioningViews(mTransitioningViews);
@@ -330,7 +332,21 @@
         mResultReceiver = resultReceiver;
     }
 
-    protected abstract Transition getViewsTransition();
+    protected Transition getViewsTransition() {
+        if (mIsReturning) {
+            return getWindow().getExitTransition();
+        } else {
+            return getWindow().getEnterTransition();
+        }
+    }
+
+    protected Transition getSharedElementTransition() {
+        if (mIsReturning) {
+            return getWindow().getSharedElementExitTransition();
+        } else {
+            return getWindow().getSharedElementEnterTransition();
+        }
+    }
 
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
@@ -342,4 +358,5 @@
             return mEpicenter;
         }
     }
+
 }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 636205b..b40d16c 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -51,7 +51,6 @@
     private static final long MAX_WAIT_MS = 1500;
 
     private boolean mSharedElementTransitionStarted;
-    private boolean mIsReturning;
     private Activity mActivity;
     private boolean mHasStopped;
     private Handler mHandler;
@@ -61,9 +60,8 @@
             ArrayList<String> sharedElementNames,
             ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
         super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
-                activity.mTransitionListener);
+                getListener(activity, acceptedNames), acceptedNames != null);
         mActivity = activity;
-        mIsReturning = acceptedNames != null;
         setResultReceiver(resultReceiver);
         prepareEnter();
         Bundle resultReceiverBundle = new Bundle();
@@ -80,6 +78,12 @@
         }
     }
 
+    private static SharedElementListener getListener(Activity activity,
+            ArrayList<String> acceptedNames) {
+        boolean isReturning = acceptedNames != null;
+        return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener;
+    }
+
     @Override
     protected void onReceiveResult(int resultCode, Bundle resultData) {
         switch (resultCode) {
@@ -299,7 +303,6 @@
             if (sharedElementBundle != null) {
                 Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
                 View snapshot = new View(context);
-                snapshot.setId(com.android.internal.R.id.shared_element);
                 Resources resources = getWindow().getContext().getResources();
                 snapshot.setBackground(new BitmapDrawable(resources, bitmap));
                 snapshot.setViewName(name);
@@ -420,12 +423,4 @@
         }
     }
 
-    @Override
-    protected Transition getViewsTransition() {
-        return getWindow().getEnterTransition();
-    }
-
-    protected Transition getSharedElementTransition() {
-        return getWindow().getSharedElementEnterTransition();
-    }
 }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 43a60a3..1d78b30 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -53,20 +53,22 @@
 
     private boolean mIsBackgroundReady;
 
-    private boolean mIsReturning;
-
     private boolean mIsCanceled;
 
     private Handler mHandler;
 
     public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
-        super(activity.getWindow(), names, accepted, mapped, activity.mTransitionListener);
-        mIsReturning = isReturning;
+        super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
+                isReturning);
         mIsBackgroundReady = !mIsReturning;
         mActivity = activity;
     }
 
+    private static SharedElementListener getListener(Activity activity, boolean isReturning) {
+        return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener;
+    }
+
     @Override
     protected void onReceiveResult(int resultCode, Bundle resultData) {
         switch (resultCode) {
@@ -271,13 +273,4 @@
         }
         return -1;
     }
-
-    @Override
-    protected Transition getViewsTransition() {
-        return getWindow().getExitTransition();
-    }
-
-    protected Transition getSharedElementTransition() {
-        return getWindow().getSharedElementExitTransition();
-    }
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fd76b9c4..59b3a27 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -45,6 +45,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.text.NumberFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * A class that represents how a persistent notification is to be presented to
@@ -370,6 +371,14 @@
      */
     public static final int FLAG_LOCAL_ONLY         = 0x00000100;
 
+    /**
+     * Bit to be bitswise-ored into the {@link #flags} field that should be
+     * set if this notification is the group summary for a group of notifications.
+     * Grouped notifications may display in a cluster or stack on devices which
+     * support such rendering. Requires a group key also be set using {@link Builder#setGroup}.
+     */
+    public static final int FLAG_GROUP_SUMMARY      = 0x00000200;
+
     public int flags;
 
     /** @hide */
@@ -539,6 +548,34 @@
      */
     public String category;
 
+    private String mGroupKey;
+
+    /**
+     * Get the key used to group this notification into a cluster or stack
+     * with other notifications on devices which support such rendering.
+     */
+    public String getGroup() {
+        return mGroupKey;
+    }
+
+    private String mSortKey;
+
+    /**
+     * Get a sort key that orders this notification among other notifications from the
+     * same package. This can be useful if an external sort was already applied and an app
+     * would like to preserve this. Notifications will be sorted lexicographically using this
+     * value, although providing different priorities in addition to providing sort key may
+     * cause this value to be ignored.
+     *
+     * <p>This sort key can also be used to order members of a notification group. See
+     * {@link Builder#setGroup}.
+     *
+     * @see String#compareTo(String)
+     */
+    public String getSortKey() {
+        return mSortKey;
+    }
+
     /**
      * Additional semantic data to be carried around with this Notification.
      * <p>
@@ -706,15 +743,18 @@
      */
     public static class Action implements Parcelable {
         private final Bundle mExtras;
+        private RemoteInput[] mRemoteInputs;
 
         /**
          * Small icon representing the action.
          */
         public int icon;
+
         /**
          * Title of the action.
          */
         public CharSequence title;
+
         /**
          * Intent to send when the user invokes this action. May be null, in which case the action
          * may be rendered in a disabled presentation by the system UI.
@@ -728,19 +768,23 @@
                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
             mExtras = in.readBundle();
+            mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR);
         }
+
         /**
          * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}.
          */
         public Action(int icon, CharSequence title, PendingIntent intent) {
-            this(icon, title, intent, new Bundle());
+            this(icon, title, intent, new Bundle(), null);
         }
 
-        private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
+        private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras,
+                RemoteInput[] remoteInputs) {
             this.icon = icon;
             this.title = title;
             this.actionIntent = intent;
             this.mExtras = extras != null ? extras : new Bundle();
+            this.mRemoteInputs = remoteInputs;
         }
 
         /**
@@ -751,13 +795,22 @@
         }
 
         /**
+         * Get the list of inputs to be collected from the user when this action is sent.
+         * May return null if no remote inputs were added.
+         */
+        public RemoteInput[] getRemoteInputs() {
+            return mRemoteInputs;
+        }
+
+        /**
          * Builder class for {@link Action} objects.
          */
-        public static class Builder {
+        public static final class Builder {
             private final int mIcon;
             private final CharSequence mTitle;
             private final PendingIntent mIntent;
             private final Bundle mExtras;
+            private ArrayList<RemoteInput> mRemoteInputs;
 
             /**
              * Construct a new builder for {@link Action} object.
@@ -766,7 +819,7 @@
              * @param intent the {@link PendingIntent} to fire when users trigger this action
              */
             public Builder(int icon, CharSequence title, PendingIntent intent) {
-                this(icon, title, intent, new Bundle());
+                this(icon, title, intent, new Bundle(), null);
             }
 
             /**
@@ -775,14 +828,20 @@
              * @param action the action to read fields from.
              */
             public Builder(Action action) {
-                this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
+                this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras),
+                        action.getRemoteInputs());
             }
 
-            private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
+            private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras,
+                    RemoteInput[] remoteInputs) {
                 mIcon = icon;
                 mTitle = title;
                 mIntent = intent;
                 mExtras = extras;
+                if (remoteInputs != null) {
+                    mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
+                    Collections.addAll(mRemoteInputs, remoteInputs);
+                }
             }
 
             /**
@@ -809,22 +868,62 @@
             }
 
             /**
+             * Add an input to be collected from the user when this action is sent.
+             * Response values can be retrieved from the fired intent by using the
+             * {@link RemoteInput#getResultsFromIntent} function.
+             * @param remoteInput a {@link RemoteInput} to add to the action
+             * @return this object for method chaining
+             */
+            public Builder addRemoteInput(RemoteInput remoteInput) {
+                if (mRemoteInputs == null) {
+                    mRemoteInputs = new ArrayList<RemoteInput>();
+                }
+                mRemoteInputs.add(remoteInput);
+                return this;
+            }
+
+            /**
+             * Apply an extender to this action builder. Extenders may be used to add
+             * metadata or change options on this builder.
+             */
+            public Builder apply(Extender extender) {
+                extender.applyTo(this);
+                return this;
+            }
+
+            /**
+             * Extender interface for use with {@link #apply}. Extenders may be used to add
+             * metadata or change options on this builder.
+             */
+            public interface Extender {
+                /**
+                 * Apply this extender to a notification action builder.
+                 * @param builder the builder to be modified.
+                 * @return the build object for chaining.
+                 */
+                public Builder applyTo(Builder builder);
+            }
+
+            /**
              * Combine all of the options that have been set and return a new {@link Action}
              * object.
              * @return the built action
              */
             public Action build() {
-                return new Action(mIcon, mTitle, mIntent, mExtras);
+                RemoteInput[] remoteInputs = mRemoteInputs != null
+                        ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
+                return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs);
             }
         }
 
         @Override
         public Action clone() {
             return new Action(
-                this.icon,
-                this.title,
-                this.actionIntent, // safe to alias
-                new Bundle(this.mExtras));
+                    icon,
+                    title,
+                    actionIntent, // safe to alias
+                    new Bundle(mExtras),
+                    getRemoteInputs());
         }
         @Override
         public int describeContents() {
@@ -841,6 +940,7 @@
                 out.writeInt(0);
             }
             out.writeBundle(mExtras);
+            out.writeTypedArray(mRemoteInputs, flags);
         }
         public static final Parcelable.Creator<Action> CREATOR =
                 new Parcelable.Creator<Action>() {
@@ -960,6 +1060,10 @@
 
         category = parcel.readString();
 
+        mGroupKey = parcel.readString();
+
+        mSortKey = parcel.readString();
+
         extras = parcel.readBundle(); // may be null
 
         actions = parcel.createTypedArray(Action.CREATOR); // may be null
@@ -1037,6 +1141,10 @@
 
         that.category = this.category;
 
+        that.mGroupKey = this.mGroupKey;
+
+        that.mSortKey = this.mSortKey;
+
         if (this.extras != null) {
             try {
                 that.extras = new Bundle(this.extras);
@@ -1188,6 +1296,10 @@
 
         parcel.writeString(category);
 
+        parcel.writeString(mGroupKey);
+
+        parcel.writeString(mSortKey);
+
         parcel.writeBundle(extras); // null ok
 
         parcel.writeTypedArray(actions, 0); // null ok
@@ -1325,7 +1437,18 @@
         sb.append(" flags=0x");
         sb.append(Integer.toHexString(this.flags));
         sb.append(String.format(" color=0x%08x", this.color));
-        sb.append(" category="); sb.append(this.category);
+        if (this.category != null) {
+            sb.append(" category=");
+            sb.append(this.category);
+        }
+        if (this.mGroupKey != null) {
+            sb.append(" groupKey=");
+            sb.append(this.mGroupKey);
+        }
+        if (this.mSortKey != null) {
+            sb.append(" sortKey=");
+            sb.append(this.mSortKey);
+        }
         if (actions != null) {
             sb.append(" ");
             sb.append(actions.length);
@@ -1408,6 +1531,8 @@
         private int mProgress;
         private boolean mProgressIndeterminate;
         private String mCategory;
+        private String mGroupKey;
+        private String mSortKey;
         private Bundle mExtras;
         private int mPriority;
         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
@@ -1839,6 +1964,51 @@
         }
 
         /**
+         * Set this notification to be part of a group of notifications sharing the same key.
+         * Grouped notifications may display in a cluster or stack on devices which
+         * support such rendering.
+         *
+         * <p>To make this notification the summary for its group, also call
+         * {@link #setGroupSummary}. A sort order can be specified for group members by using
+         * {@link #setSortKey}.
+         * @param groupKey The group key of the group.
+         * @return this object for method chaining
+         */
+        public Builder setGroup(String groupKey) {
+            mGroupKey = groupKey;
+            return this;
+        }
+
+        /**
+         * Set this notification to be the group summary for a group of notifications.
+         * Grouped notifications may display in a cluster or stack on devices which
+         * support such rendering. Requires a group key also be set using {@link #setGroup}.
+         * @param isGroupSummary Whether this notification should be a group summary.
+         * @return this object for method chaining
+         */
+        public Builder setGroupSummary(boolean isGroupSummary) {
+            setFlag(FLAG_GROUP_SUMMARY, isGroupSummary);
+            return this;
+        }
+
+        /**
+         * Set a sort key that orders this notification among other notifications from the
+         * same package. This can be useful if an external sort was already applied and an app
+         * would like to preserve this. Notifications will be sorted lexicographically using this
+         * value, although providing different priorities in addition to providing sort key may
+         * cause this value to be ignored.
+         *
+         * <p>This sort key can also be used to order members of a notification group. See
+         * {@link #setGroup}.
+         *
+         * @see String#compareTo(String)
+         */
+        public Builder setSortKey(String sortKey) {
+            mSortKey = sortKey;
+            return this;
+        }
+
+        /**
          * Merge additional metadata into this notification.
          *
          * <p>Values within the Bundle will replace existing extras values in this Builder.
@@ -1949,7 +2119,7 @@
 
         /**
          * Specify the value of {@link #visibility}.
-
+         *
          * @param visibility One of {@link #VISIBILITY_PRIVATE} (the default),
          * {@link #VISIBILITY_SECRET}, or {@link #VISIBILITY_PUBLIC}.
          *
@@ -1971,6 +2141,28 @@
             return this;
         }
 
+        /**
+         * Apply an extender to this notification builder. Extenders may be used to add
+         * metadata or change options on this builder.
+         */
+        public Builder apply(Extender extender) {
+            extender.applyTo(this);
+            return this;
+        }
+
+        /**
+         * Extender interface for use with {@link #apply}. Extenders may be used to add
+         * metadata or change options on this builder.
+         */
+        public interface Extender {
+            /**
+             * Apply this extender to a notification builder.
+             * @param builder the builder to be modified.
+             * @return the build object for chaining.
+             */
+            public Builder applyTo(Builder builder);
+        }
+
         private void setFlag(int mask, boolean value) {
             if (value) {
                 mFlags |= mask;
@@ -2298,6 +2490,8 @@
                 n.flags |= FLAG_SHOW_LIGHTS;
             }
             n.category = mCategory;
+            n.mGroupKey = mGroupKey;
+            n.mSortKey = mSortKey;
             n.priority = mPriority;
             if (mActions.size() > 0) {
                 n.actions = new Action[mActions.size()];
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
new file mode 100644
index 0000000..9cfc541
--- /dev/null
+++ b/core/java/android/app/RemoteInput.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A {@code RemoteInput} object specifies input to be collected from a user to be passed along with
+ * an intent inside a {@link android.app.PendingIntent} that is sent.
+ * Always use {@link RemoteInput.Builder} to create instances of this class.
+ * <p class="note"> See
+ * <a href="{@docRoot}wear/notifications/remote-input.html">Receiving Voice Input from
+ * a Notification</a> for more information on how to use this class.
+ *
+ * <p>The following example adds a {@code RemoteInput} to a {@link Notification.Action},
+ * sets the result key as {@code quick_reply}, and sets the label as {@code Quick reply}.
+ * Users are prompted to input a response when they trigger the action. The results are sent along
+ * with the intent and can be retrieved with the result key (provided to the {@link Builder}
+ * constructor) from the Bundle returned by {@link #getResultsFromIntent}.
+ *
+ * <pre class="prettyprint">
+ * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
+ * Notification.Action action = new Notification.Action.Builder(
+ *         R.drawable.reply, &quot;Reply&quot;, actionIntent)
+ *         <b>.addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
+ *                 .setLabel("Quick reply").build()</b>)
+ *         .build();</pre>
+ *
+ * <p>When the {@link android.app.PendingIntent} is fired, the intent inside will contain the
+ * input results if collected. To access these results, use the {@link #getResultsFromIntent}
+ * function. The result values will present under the result key passed to the {@link Builder}
+ * constructor.
+ *
+ * <pre class="prettyprint">
+ * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
+ * Bundle results = RemoteInput.getResultsFromIntent(intent);
+ * if (results != null) {
+ *     CharSequence quickReplyResult = results.getCharSequence(KEY_QUICK_REPLY_TEXT);
+ * }</pre>
+ */
+public final class RemoteInput implements Parcelable {
+    /** Label used to denote the clip data type used for remote input transport */
+    public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+
+    /** Extra added to a clip data intent object to hold the results bundle. */
+    public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+
+    private final String mResultKey;
+    private final CharSequence mLabel;
+    private final CharSequence[] mChoices;
+    private final boolean mAllowFreeFormInput;
+    private final Bundle mExtras;
+
+    private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
+            boolean allowFreeFormInput, Bundle extras) {
+        this.mResultKey = resultKey;
+        this.mLabel = label;
+        this.mChoices = choices;
+        this.mAllowFreeFormInput = allowFreeFormInput;
+        this.mExtras = extras;
+    }
+
+    /**
+     * Get the key that the result of this input will be set in from the Bundle returned by
+     * {@link #getResultsFromIntent} when the {@link android.app.PendingIntent} is sent.
+     */
+    public String getResultKey() {
+        return mResultKey;
+    }
+
+    /**
+     * Get the label to display to users when collecting this input.
+     */
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Get possible input choices. This can be {@code null} if there are no choices to present.
+     */
+    public CharSequence[] getChoices() {
+        return mChoices;
+    }
+
+    /**
+     * Get whether or not users can provide an arbitrary value for
+     * input. If you set this to {@code false}, users must select one of the
+     * choices in {@link #getChoices}. An {@link IllegalArgumentException} is thrown
+     * if you set this to false and {@link #getChoices} returns {@code null} or empty.
+     */
+    public boolean getAllowFreeFormInput() {
+        return mAllowFreeFormInput;
+    }
+
+    /**
+     * Get additional metadata carried around with this remote input.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Builder class for {@link RemoteInput} objects.
+     */
+    public static final class Builder {
+        private final String mResultKey;
+        private CharSequence mLabel;
+        private CharSequence[] mChoices;
+        private boolean mAllowFreeFormInput = true;
+        private Bundle mExtras = new Bundle();
+
+        /**
+         * Create a builder object for {@link RemoteInput} objects.
+         * @param resultKey the Bundle key that refers to this input when collected from the user
+         */
+        public Builder(String resultKey) {
+            if (resultKey == null) {
+                throw new IllegalArgumentException("Result key can't be null");
+            }
+            mResultKey = resultKey;
+        }
+
+        /**
+         * Set a label to be displayed to the user when collecting this input.
+         * @param label The label to show to users when they input a response.
+         * @return this object for method chaining
+         */
+        public Builder setLabel(CharSequence label) {
+            mLabel = Notification.safeCharSequence(label);
+            return this;
+        }
+
+        /**
+         * Specifies choices available to the user to satisfy this input.
+         * @param choices an array of pre-defined choices for users input.
+         *        You must provide a non-null and non-empty array if
+         *        you disabled free form input using {@link #setAllowFreeFormInput}.
+         * @return this object for method chaining
+         */
+        public Builder setChoices(CharSequence[] choices) {
+            if (choices == null) {
+                mChoices = null;
+            } else {
+                mChoices = new CharSequence[choices.length];
+                for (int i = 0; i < choices.length; i++) {
+                    mChoices[i] = Notification.safeCharSequence(choices[i]);
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Specifies whether the user can provide arbitrary values.
+         *
+         * @param allowFreeFormInput The default is {@code true}.
+         *         If you specify {@code false}, you must provide a non-null
+         *         and non-empty array to {@link #setChoices} or an
+         *         {@link IllegalArgumentException} is thrown.
+         * @return this object for method chaining
+         */
+        public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
+            mAllowFreeFormInput = allowFreeFormInput;
+            return this;
+        }
+
+        /**
+         * Merge additional metadata into this builder.
+         *
+         * <p>Values within the Bundle will replace existing extras values in this Builder.
+         *
+         * @see RemoteInput#getExtras
+         */
+        public Builder addExtras(Bundle extras) {
+            if (extras != null) {
+                mExtras.putAll(extras);
+            }
+            return this;
+        }
+
+        /**
+         * Get the metadata Bundle used by this Builder.
+         *
+         * <p>The returned Bundle is shared with this Builder.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Combine all of the options that have been set and return a new {@link RemoteInput}
+         * object.
+         */
+        public RemoteInput build() {
+            return new RemoteInput(mResultKey, mLabel, mChoices, mAllowFreeFormInput, mExtras);
+        }
+    }
+
+    private RemoteInput(Parcel in) {
+        mResultKey = in.readString();
+        mLabel = in.readCharSequence();
+        mChoices = in.readCharSequenceArray();
+        mAllowFreeFormInput = in.readInt() != 0;
+        mExtras = in.readBundle();
+    }
+
+    /**
+     * Get the remote input results bundle from an intent. The returned Bundle will
+     * contain a key/value for every result key populated by remote input collector.
+     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
+     * @param intent The intent object that fired in response to an action or content intent
+     *               which also had one or more remote input requested.
+     */
+    public static Bundle getResultsFromIntent(Intent intent) {
+        ClipData clipData = intent.getClipData();
+        if (clipData == null) {
+            return null;
+        }
+        ClipDescription clipDescription = clipData.getDescription();
+        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+            return null;
+        }
+        if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
+            return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA);
+        }
+        return null;
+    }
+
+    /**
+     * Populate an intent object with the results gathered from remote input. This method
+     * should only be called by remote input collection services when sending results to a
+     * pending intent.
+     * @param remoteInputs The remote inputs for which results are being provided
+     * @param intent The intent to add remote inputs to. The {@link ClipData}
+     *               field of the intent will be modified to contain the results.
+     * @param results A bundle holding the remote input results. This bundle should
+     *                be populated with keys matching the result keys specified in
+     *                {@code remoteInputs} with values being the result per key.
+     */
+    public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
+            Bundle results) {
+        Bundle resultsBundle = new Bundle();
+        for (RemoteInput remoteInput : remoteInputs) {
+            Object result = results.get(remoteInput.getResultKey());
+            if (result instanceof CharSequence) {
+                resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
+            }
+        }
+        Intent clipIntent = new Intent();
+        clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent));
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mResultKey);
+        out.writeCharSequence(mLabel);
+        out.writeCharSequenceArray(mChoices);
+        out.writeInt(mAllowFreeFormInput ? 1 : 0);
+        out.writeBundle(mExtras);
+    }
+
+    public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() {
+        @Override
+        public RemoteInput createFromParcel(Parcel in) {
+            return new RemoteInput(in);
+        }
+
+        @Override
+        public RemoteInput[] newArray(int size) {
+            return new RemoteInput[size];
+        }
+    };
+}
diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementListener.java
index d4bc019..e03e42e 100644
--- a/core/java/android/app/SharedElementListener.java
+++ b/core/java/android/app/SharedElementListener.java
@@ -22,15 +22,27 @@
 
 /**
  * Listener provided in
- * {@link Activity#setSharedElementListener(SharedElementListener)}
- * to monitor the Activity transitions. The events can be used to customize or override Activity
+ * {@link Activity#setEnterSharedElementListener(SharedElementListener)} and
+ * {@link Activity#setExitSharedElementListener(SharedElementListener)}
+ * to monitor the Activity transitions. The events can be used to customize Activity
  * Transition behavior.
  */
-public class SharedElementListener {
+public abstract class SharedElementListener {
+
+    static final SharedElementListener NULL_LISTENER = new SharedElementListener() {
+    };
+
     /**
-     * Called to allow the listener to customize the start state of the shared element for
-     * the shared element entering transition. By default, the shared element is placed in
-     * the position and with the size of the shared element in the calling Activity or Fragment.
+     * Called to allow the listener to customize the start state of the shared element when
+     * transferring in shared element state.
+     * <p>
+     *     The shared element will start at the size and position of the shared element
+     *     in the launching Activity or Fragment. It will also transfer ImageView scaleType
+     *     and imageMatrix if the shared elements in the calling and called Activities are
+     *     ImageViews. Some applications may want to make additional changes, such as
+     *     changing the clip bounds, scaling, or rotation if the shared element end state
+     *     does not map well to the start state.
+     * </p>
      *
      * @param sharedElementNames The names of the shared elements that were accepted into
      *                           the View hierarchy.
@@ -44,8 +56,17 @@
             List<View> sharedElements, List<View> sharedElementSnapshots) {}
 
     /**
-     * Called to allow the listener to customize the end state of the shared element for
-     * the shared element entering transition.
+     * Called to allow the listener to customize the end state of the shared element when
+     * transferring in shared element state.
+     * <p>
+     *     Any customization done in
+     *     {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)}
+     *     may need to be modified to the final state of the shared element if it is not
+     *     automatically corrected by layout. For example, rotation or scale will not
+     *     be affected by layout and if changed in {@link #setSharedElementStart(java.util.List,
+     *     java.util.List, java.util.List)}, it will also have to be set here again to correct
+     *     the end state.
+     * </p>
      *
      * @param sharedElementNames The names of the shared elements that were accepted into
      *                           the View hierarchy.
@@ -59,13 +80,18 @@
             List<View> sharedElements, List<View> sharedElementSnapshots) {}
 
     /**
-     * If nothing is done, all shared elements that were not accepted by
-     * {@link #remapSharedElements(java.util.List, java.util.Map)} will be Transitioned
-     * out of the entering scene automatically. Any elements removed from
-     * rejectedSharedElements must be handled by the ActivityTransitionListener.
-     * <p>Views in rejectedSharedElements will have their position and size set to the
-     * position of the calling shared element, relative to the Window decor View. This
-     * view may be safely added to the decor View's overlay to remain in position.</p>
+     * Called after {@link #remapSharedElements(java.util.List, java.util.Map)} when
+     * transferring shared elements in. Any shared elements that have no mapping will be in
+     * <var>rejectedSharedElements</var>. The elements remaining in
+     * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a
+     * View is removed from <var>rejectedSharedElements</var>, it must be handled by the
+     * <code>SharedElementListener</code>.
+     * <p>
+     * Views in rejectedSharedElements will have their position and size set to the
+     * position of the calling shared element, relative to the Window decor View and contain
+     * snapshots of the View from the calling Activity or Fragment. This
+     * view may be safely added to the decor View's overlay to remain in position.
+     * </p>
      *
      * @param rejectedSharedElements Views containing visual information of shared elements
      *                               that are not part of the entering scene. These Views
@@ -78,6 +104,7 @@
     /**
      * Lets the ActivityTransitionListener adjust the mapping of shared element names to
      * Views.
+     *
      * @param names The names of all shared elements transferred from the calling Activity
      *              to the started Activity.
      * @param sharedElements The mapping of shared element names to Views. The best guess
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 58d707c..48ff5b6 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -911,6 +911,35 @@
      */
     public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
         try {
+            /**
+             * The framework makes no attempt to limit the window size
+             * to the maximum texture size. Any window larger than this
+             * cannot be composited.
+             *
+             * Read maximum texture size from system property and scale down
+             * minimumWidth and minimumHeight accordingly.
+             */
+            int maximumTextureSize;
+            try {
+                maximumTextureSize = SystemProperties.getInt("sys.max_texture_size", 0);
+            } catch (Exception e) {
+                maximumTextureSize = 0;
+            }
+
+            if (maximumTextureSize > 0) {
+                if ((minimumWidth > maximumTextureSize) ||
+                    (minimumHeight > maximumTextureSize)) {
+                    float aspect = (float)minimumHeight / (float)minimumWidth;
+                    if (minimumWidth > minimumHeight) {
+                        minimumWidth = maximumTextureSize;
+                        minimumHeight = (int)((minimumWidth * aspect) + 0.5);
+                    } else {
+                        minimumHeight = maximumTextureSize;
+                        minimumWidth = (int)((minimumHeight / aspect) + 0.5);
+                    }
+                }
+            }
+
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
             } else {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8884446..18e2a95 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -32,6 +32,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.trust.TrustAgentService;
 import android.util.Log;
 
@@ -2050,6 +2051,68 @@
     }
 
     /**
+     * Called by device or profile owner to block or unblock packages. When a package is blocked it
+     * is unavailable for use, but the data and actual package file remain.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The name of the package to block or unblock.
+     * @param blocked {@code true} if the package should be blocked, {@code false} if it should be
+     *                 unblocked.
+     * @return boolean Whether the blocked setting of the package was successfully updated.
+     */
+    public boolean setApplicationBlocked(ComponentName admin, String packageName,
+            boolean blocked) {
+        if (mService != null) {
+            try {
+                return mService.setApplicationBlocked(admin, packageName, blocked);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by profile or device owner to block or unblock currently installed packages. This
+     * should only be called by a profile or device owner running within a managed profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param intent An intent matching the app(s) to be updated. All apps that resolve for this
+     *               intent will be updated in the current profile.
+     * @param blocked {@code true} if the packages should be blocked, {@code false} if they should
+     *                 be unblocked.
+     * @return int The number of activities that matched the intent and were updated.
+     */
+    public int setApplicationsBlocked(ComponentName admin, Intent intent, boolean blocked) {
+        if (mService != null) {
+            try {
+                return mService.setApplicationsBlocked(admin, intent, blocked);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Called by device or profile owner to determine if a package is blocked.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The name of the package to retrieve the blocked status of.
+     * @return boolean {@code true} if the package is blocked, {@code false} otherwise.
+     */
+    public boolean isApplicationBlocked(ComponentName admin, String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isApplicationBlocked(admin, packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by profile or device owner to re-enable a system app that was disabled by default
      * when the managed profile was created. This should only be called from a profile or device
      * owner running within a managed profile.
@@ -2181,4 +2244,42 @@
         }
         return false;
     }
+
+    /**
+     * Called by device owners to update {@link Settings.Global} settings. Validation that the value
+     * of the setting is in the correct form for the setting type should be performed by the caller.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param setting The name of the setting to update.
+     * @param value The value to update the setting to.
+     */
+    public void setGlobalSetting(ComponentName admin, String setting, String value) {
+        if (mService != null) {
+            try {
+                mService.setGlobalSetting(admin, setting, value);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Called by profile or device owners to update {@link Settings.Secure} settings. Validation
+     * that the value of the setting is in the correct form for the setting type should be performed
+     * by the caller.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param setting The name of the setting to update.
+     * @param value The value to update the setting to.
+     */
+    public void setSecureSetting(ComponentName admin, String setting, String value) {
+        if (mService != null) {
+            try {
+                mService.setSecureSetting(admin, setting, value);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 03ced0f..7257158 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -124,6 +124,10 @@
     void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearForwardingIntentFilters(in ComponentName admin);
 
+    boolean setApplicationBlocked(in ComponentName admin, in String packageName, boolean blocked);
+    int setApplicationsBlocked(in ComponentName admin, in Intent intent, boolean blocked);
+    boolean isApplicationBlocked(in ComponentName admin, in String packageName);
+
     void enableSystemApp(in ComponentName admin, in String packageName);
     int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
 
@@ -133,4 +137,7 @@
     void setLockTaskComponents(in ComponentName[] components);
     ComponentName[] getLockTaskComponents();
     boolean isLockTaskPermitted(in ComponentName component);
+
+    void setGlobalSetting(in ComponentName who, in String setting, in String value);
+    void setSecureSetting(in ComponentName who, in String setting, in String value);
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e79deec..9e1c995 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -498,6 +498,34 @@
     }
 
     /**
+     * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
+     */
+    public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
+        // TODO: Return null if this feature is not supported by hardware.
+        try {
+            IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+            return new BluetoothLeAdvertiser(iGatt);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
+     */
+    public BluetoothLeScanner getBluetoothLeScanner() {
+        // TODO: Return null if BLE scan is not supported by hardware.
+        try {
+            IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+            return new BluetoothLeScanner(iGatt);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e);
+            return null;
+        }
+    }
+
+    /**
      * Interface for BLE advertising callback.
      *
      * @hide
@@ -2024,6 +2052,10 @@
             }
         }
 
+        @Override
+        public void onMultiAdvertiseCallback(int status) {
+            // no op
+        }
         /**
          * Callback reporting LE ATT MTU.
          * @hide
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 601d9ee..c9df9c0 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -581,7 +581,15 @@
             public void onAdvertiseStateChange(int state, int status) {
                 if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
                         + state + " status=" + status);
-	    }
+            }
+
+            /**
+             * @hide
+             */
+            @Override
+            public void onMultiAdvertiseCallback(int status) {
+                // no op.
+            }
 
             /**
              * Callback invoked when the MTU for a given connection changes
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/bluetooth/BluetoothLeAdvertiseScanData.aidl
similarity index 72%
copy from core/java/android/service/notification/NotificationOrderUpdate.aidl
copy to core/java/android/bluetooth/BluetoothLeAdvertiseScanData.aidl
index 5d50641..4aa8881 100644
--- a/core/java/android/service/notification/NotificationOrderUpdate.aidl
+++ b/core/java/android/bluetooth/BluetoothLeAdvertiseScanData.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.notification;
+package android.bluetooth;
 
-parcelable NotificationOrderUpdate;
+parcelable BluetoothLeAdvertiseScanData.AdvertisementData;
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothLeAdvertiseScanData.java b/core/java/android/bluetooth/BluetoothLeAdvertiseScanData.java
new file mode 100644
index 0000000..d12ac6c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeAdvertiseScanData.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents Bluetooth LE advertise and scan response data. This could be either the advertisement
+ * data to be advertised, or the scan record obtained from BLE scans.
+ * <p>
+ * The exact bluetooth advertising and scan response data fields and types are defined in Bluetooth
+ * 4.0 specification, Volume 3, Part C, Section 11 and 18, as well as Supplement to the Bluetooth
+ * Core Specification Version 4. Currently the following fields are allowed to be set:
+ * <li>Service UUIDs which identify the bluetooth gatt services running on the device.
+ * <li>Tx power level which is the transmission power level.
+ * <li>Service data which is the data associated with a service.
+ * <li>Manufacturer specific data which is the data associated with a particular manufacturer.
+ *
+ * @see BluetoothLeAdvertiser
+ */
+public final class BluetoothLeAdvertiseScanData {
+    private static final String TAG = "BluetoothLeAdvertiseScanData";
+
+    /**
+     * Bluetooth LE Advertising Data type, the data will be placed in AdvData field of advertising
+     * packet.
+     */
+    public static final int ADVERTISING_DATA = 0;
+    /**
+     * Bluetooth LE scan response data, the data will be placed in ScanRspData field of advertising
+     * packet.
+     * <p>
+     * TODO: unhide when stack supports setting scan response data.
+     *
+     * @hide
+     */
+    public static final int SCAN_RESPONSE_DATA = 1;
+    /**
+     * Scan record parsed from Bluetooth LE scans. The content can contain a concatenation of
+     * advertising data and scan response data.
+     */
+    public static final int PARSED_SCAN_RECORD = 2;
+
+    /**
+     * Base data type which contains the common fields for {@link AdvertisementData} and
+     * {@link ScanRecord}.
+     */
+    public abstract static class AdvertiseBaseData {
+
+        private final int mDataType;
+
+        @Nullable
+        private final List<ParcelUuid> mServiceUuids;
+
+        private final int mManufacturerId;
+        @Nullable
+        private final byte[] mManufacturerSpecificData;
+
+        @Nullable
+        private final ParcelUuid mServiceDataUuid;
+        @Nullable
+        private final byte[] mServiceData;
+
+        private AdvertiseBaseData(int dataType,
+                List<ParcelUuid> serviceUuids,
+                ParcelUuid serviceDataUuid, byte[] serviceData,
+                int manufacturerId,
+                byte[] manufacturerSpecificData) {
+            mDataType = dataType;
+            mServiceUuids = serviceUuids;
+            mManufacturerId = manufacturerId;
+            mManufacturerSpecificData = manufacturerSpecificData;
+            mServiceDataUuid = serviceDataUuid;
+            mServiceData = serviceData;
+        }
+
+        /**
+         * Returns the type of data, indicating whether the data is advertising data, scan response
+         * data or scan record.
+         */
+        public int getDataType() {
+            return mDataType;
+        }
+
+        /**
+         * Returns a list of service uuids within the advertisement that are used to identify the
+         * bluetooth gatt services.
+         */
+        public List<ParcelUuid> getServiceUuids() {
+            return mServiceUuids;
+        }
+
+        /**
+         * Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
+         * SIG.
+         */
+        public int getManufacturerId() {
+            return mManufacturerId;
+        }
+
+        /**
+         * Returns the manufacturer specific data which is the content of manufacturer specific data
+         * field. The first 2 bytes of the data contain the company id.
+         */
+        public byte[] getManufacturerSpecificData() {
+            return mManufacturerSpecificData;
+        }
+
+        /**
+         * Returns a 16 bit uuid of the service that the service data is associated with.
+         */
+        public ParcelUuid getServiceDataUuid() {
+            return mServiceDataUuid;
+        }
+
+        /**
+         * Returns service data. The first two bytes should be a 16 bit service uuid associated with
+         * the service data.
+         */
+        public byte[] getServiceData() {
+            return mServiceData;
+        }
+
+        @Override
+        public String toString() {
+            return "AdvertiseBaseData [mDataType=" + mDataType + ", mServiceUuids=" + mServiceUuids
+                    + ", mManufacturerId=" + mManufacturerId + ", mManufacturerSpecificData="
+                    + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
+                    + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData) + "]";
+        }
+    }
+
+    /**
+     * Advertisement data packet for Bluetooth LE advertising. This represents the data to be
+     * broadcasted in Bluetooth LE advertising.
+     * <p>
+     * Use {@link AdvertisementData.Builder} to create an instance of {@link AdvertisementData} to
+     * be advertised.
+     *
+     * @see BluetoothLeAdvertiser
+     */
+    public static final class AdvertisementData extends AdvertiseBaseData implements Parcelable {
+
+        private boolean mIncludeTxPowerLevel;
+
+        /**
+         * Whether the transmission power level will be included in the advertisement packet.
+         */
+        public boolean getIncludeTxPowerLevel() {
+            return mIncludeTxPowerLevel;
+        }
+
+        /**
+         * Returns a {@link Builder} to build {@link AdvertisementData}.
+         */
+        public static Builder newBuilder() {
+            return new Builder();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(getDataType());
+            List<ParcelUuid> uuids = getServiceUuids();
+            if (uuids == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(uuids.size());
+                dest.writeList(uuids);
+            }
+
+            dest.writeInt(getManufacturerId());
+            byte[] manufacturerData = getManufacturerSpecificData();
+            if (manufacturerData == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(manufacturerData.length);
+                dest.writeByteArray(manufacturerData);
+            }
+
+            ParcelUuid serviceDataUuid = getServiceDataUuid();
+            if (serviceDataUuid == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(1);
+                dest.writeParcelable(serviceDataUuid, flags);
+                byte[] serviceData = getServiceData();
+                if (serviceData == null) {
+                    dest.writeInt(0);
+                } else {
+                    dest.writeInt(serviceData.length);
+                    dest.writeByteArray(serviceData);
+                }
+            }
+            dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
+        }
+
+        private AdvertisementData(int dataType,
+                List<ParcelUuid> serviceUuids,
+                ParcelUuid serviceDataUuid, byte[] serviceData,
+                int manufacturerId,
+                byte[] manufacturerSpecificData, boolean mIncludeTxPowerLevel) {
+            super(dataType, serviceUuids, serviceDataUuid, serviceData, manufacturerId,
+                    manufacturerSpecificData);
+            this.mIncludeTxPowerLevel = mIncludeTxPowerLevel;
+        }
+
+        public static final Parcelable.Creator<AdvertisementData> CREATOR =
+                new Creator<AdvertisementData>() {
+                @Override
+                    public AdvertisementData[] newArray(int size) {
+                        return new AdvertisementData[size];
+                    }
+
+                @Override
+                    public AdvertisementData createFromParcel(Parcel in) {
+                        Builder builder = newBuilder();
+                        int dataType = in.readInt();
+                        builder.dataType(dataType);
+                        if (in.readInt() > 0) {
+                            List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
+                            in.readList(uuids, ParcelUuid.class.getClassLoader());
+                            builder.serviceUuids(uuids);
+                        }
+                        int manufacturerId = in.readInt();
+                        int manufacturerDataLength = in.readInt();
+                        if (manufacturerDataLength > 0) {
+                            byte[] manufacturerData = new byte[manufacturerDataLength];
+                            in.readByteArray(manufacturerData);
+                            builder.manufacturerData(manufacturerId, manufacturerData);
+                        }
+                        if (in.readInt() == 1) {
+                            ParcelUuid serviceDataUuid = in.readParcelable(
+                                    ParcelUuid.class.getClassLoader());
+                            int serviceDataLength = in.readInt();
+                            if (serviceDataLength > 0) {
+                                byte[] serviceData = new byte[serviceDataLength];
+                                in.readByteArray(serviceData);
+                                builder.serviceData(serviceDataUuid, serviceData);
+                            }
+                        }
+                        builder.includeTxPowerLevel(in.readByte() == 1);
+                        return builder.build();
+                    }
+                };
+
+        /**
+         * Builder for {@link BluetoothLeAdvertiseScanData.AdvertisementData}. Use
+         * {@link AdvertisementData#newBuilder()} to get an instance of the Builder.
+         */
+        public static final class Builder {
+            private static final int MAX_ADVERTISING_DATA_BYTES = 31;
+            // Each fields need one byte for field length and another byte for field type.
+            private static final int OVERHEAD_BYTES_PER_FIELD = 2;
+            // Flags field will be set by system.
+            private static final int FLAGS_FIELD_BYTES = 3;
+
+            private int mDataType;
+            @Nullable
+            private List<ParcelUuid> mServiceUuids;
+            private boolean mIncludeTxPowerLevel;
+            private int mManufacturerId;
+            @Nullable
+            private byte[] mManufacturerSpecificData;
+            @Nullable
+            private ParcelUuid mServiceDataUuid;
+            @Nullable
+            private byte[] mServiceData;
+
+            /**
+             * Set data type.
+             *
+             * @param dataType Data type, could only be
+             *            {@link BluetoothLeAdvertiseScanData#ADVERTISING_DATA}
+             * @throws IllegalArgumentException If the {@code dataType} is invalid.
+             */
+            public Builder dataType(int dataType) {
+                if (mDataType != ADVERTISING_DATA && mDataType != SCAN_RESPONSE_DATA) {
+                    throw new IllegalArgumentException("invalid data type - " + dataType);
+                }
+                mDataType = dataType;
+                return this;
+            }
+
+            /**
+             * Set the service uuids. Note the corresponding bluetooth Gatt services need to be
+             * already added on the device before start BLE advertising.
+             *
+             * @param serviceUuids Service uuids to be advertised, could be 16-bit, 32-bit or
+             *            128-bit uuids.
+             * @throws IllegalArgumentException If the {@code serviceUuids} are null.
+             */
+            public Builder serviceUuids(List<ParcelUuid> serviceUuids) {
+                if (serviceUuids == null) {
+                    throw new IllegalArgumentException("serivceUuids are null");
+                }
+                mServiceUuids = serviceUuids;
+                return this;
+            }
+
+            /**
+             * Add service data to advertisement.
+             *
+             * @param serviceDataUuid A 16 bit uuid of the service data
+             * @param serviceData Service data - the first two bytes of the service data are the
+             *            service data uuid.
+             * @throws IllegalArgumentException If the {@code serviceDataUuid} or
+             *             {@code serviceData} is empty.
+             */
+            public Builder serviceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
+                if (serviceDataUuid == null || serviceData == null) {
+                    throw new IllegalArgumentException(
+                            "serviceDataUuid or serviceDataUuid is null");
+                }
+                mServiceDataUuid = serviceDataUuid;
+                mServiceData = serviceData;
+                return this;
+            }
+
+            /**
+             * Set manufacturer id and data. See <a
+             * href="https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers">assigned
+             * manufacturer identifies</a> for the existing company identifiers.
+             *
+             * @param manufacturerId Manufacturer id assigned by Bluetooth SIG.
+             * @param manufacturerSpecificData Manufacturer specific data - the first two bytes of
+             *            the manufacturer specific data are the manufacturer id.
+             * @throws IllegalArgumentException If the {@code manufacturerId} is negative or
+             *             {@code manufacturerSpecificData} is null.
+             */
+            public Builder manufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
+                if (manufacturerId < 0) {
+                    throw new IllegalArgumentException(
+                            "invalid manufacturerId - " + manufacturerId);
+                }
+                if (manufacturerSpecificData == null) {
+                    throw new IllegalArgumentException("manufacturerSpecificData is null");
+                }
+                mManufacturerId = manufacturerId;
+                mManufacturerSpecificData = manufacturerSpecificData;
+                return this;
+            }
+
+            /**
+             * Whether the transmission power level should be included in the advertising packet.
+             */
+            public Builder includeTxPowerLevel(boolean includeTxPowerLevel) {
+                mIncludeTxPowerLevel = includeTxPowerLevel;
+                return this;
+            }
+
+            /**
+             * Build the {@link BluetoothLeAdvertiseScanData}.
+             *
+             * @throws IllegalArgumentException If the data size is larger than 31 bytes.
+             */
+            public AdvertisementData build() {
+                if (totalBytes() > MAX_ADVERTISING_DATA_BYTES) {
+                    throw new IllegalArgumentException(
+                            "advertisement data size is larger than 31 bytes");
+                }
+                return new AdvertisementData(mDataType,
+                        mServiceUuids,
+                        mServiceDataUuid,
+                        mServiceData, mManufacturerId, mManufacturerSpecificData,
+                        mIncludeTxPowerLevel);
+            }
+
+            // Compute the size of the advertisement data.
+            private int totalBytes() {
+                int size = FLAGS_FIELD_BYTES; // flags field is always set.
+                if (mServiceUuids != null) {
+                    int num16BitUuids = 0;
+                    int num32BitUuids = 0;
+                    int num128BitUuids = 0;
+                    for (ParcelUuid uuid : mServiceUuids) {
+                        if (BluetoothUuid.is16BitUuid(uuid)) {
+                            ++num16BitUuids;
+                        } else if (BluetoothUuid.is32BitUuid(uuid)) {
+                            ++num32BitUuids;
+                        } else {
+                            ++num128BitUuids;
+                        }
+                    }
+                    // 16 bit service uuids are grouped into one field when doing advertising.
+                    if (num16BitUuids != 0) {
+                        size += OVERHEAD_BYTES_PER_FIELD +
+                                num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
+                    }
+                    // 32 bit service uuids are grouped into one field when doing advertising.
+                    if (num32BitUuids != 0) {
+                        size += OVERHEAD_BYTES_PER_FIELD +
+                                num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
+                    }
+                    // 128 bit service uuids are grouped into one field when doing advertising.
+                    if (num128BitUuids != 0) {
+                        size += OVERHEAD_BYTES_PER_FIELD +
+                                num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
+                    }
+                }
+                if (mServiceData != null) {
+                    size += OVERHEAD_BYTES_PER_FIELD + mServiceData.length;
+                }
+                if (mManufacturerSpecificData != null) {
+                    size += OVERHEAD_BYTES_PER_FIELD + mManufacturerSpecificData.length;
+                }
+                if (mIncludeTxPowerLevel) {
+                    size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
+                }
+                return size;
+            }
+        }
+
+    }
+
+    /**
+     * Represents a scan record from Bluetooth LE scan.
+     */
+    public static final class ScanRecord extends AdvertiseBaseData {
+        // Flags of the advertising data.
+        private final int mAdvertiseFlags;
+
+        // Transmission power level(in dB).
+        private final int mTxPowerLevel;
+
+        // Local name of the Bluetooth LE device.
+        private final String mLocalName;
+
+        /**
+         * Returns the advertising flags indicating the discoverable mode and capability of the
+         * device. Returns -1 if the flag field is not set.
+         */
+        public int getAdvertiseFlags() {
+            return mAdvertiseFlags;
+        }
+
+        /**
+         * Returns the transmission power level of the packet in dBm. Returns
+         * {@link Integer#MIN_VALUE} if the field is not set. This value can be used to calculate
+         * the path loss of a received packet using the following equation:
+         * <p>
+         * <code>pathloss = txPowerLevel - rssi</code>
+         */
+        public int getTxPowerLevel() {
+            return mTxPowerLevel;
+        }
+
+        /**
+         * Returns the local name of the BLE device. The is a UTF-8 encoded string.
+         */
+        @Nullable
+        public String getLocalName() {
+            return mLocalName;
+        }
+
+        ScanRecord(int dataType,
+                List<ParcelUuid> serviceUuids,
+                ParcelUuid serviceDataUuid, byte[] serviceData,
+                int manufacturerId,
+                byte[] manufacturerSpecificData, int advertiseFlags, int txPowerLevel,
+                String localName) {
+            super(dataType, serviceUuids, serviceDataUuid, serviceData, manufacturerId,
+                    manufacturerSpecificData);
+            mLocalName = localName;
+            mAdvertiseFlags = advertiseFlags;
+            mTxPowerLevel = txPowerLevel;
+        }
+
+        /**
+         * Get a {@link Parser} to parse the scan record byte array into {@link ScanRecord}.
+         */
+        public static Parser getParser() {
+            return new Parser();
+        }
+
+        /**
+         * A parser class used to parse a Bluetooth LE scan record to
+         * {@link BluetoothLeAdvertiseScanData}. Note not all field types would be parsed.
+         */
+        public static final class Parser {
+            private static final String PARSER_TAG = "BluetoothLeAdvertiseDataParser";
+
+            // The following data type values are assigned by Bluetooth SIG.
+            // For more details refer to Bluetooth 4.0 specification, Volume 3, Part C, Section 18.
+            private static final int DATA_TYPE_FLAGS = 0x01;
+            private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
+            private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
+            private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
+            private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
+            private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
+            private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
+            private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
+            private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
+            private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
+            private static final int DATA_TYPE_SERVICE_DATA = 0x16;
+            private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
+
+            // Helper method to extract bytes from byte array.
+            private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
+                byte[] bytes = new byte[length];
+                System.arraycopy(scanRecord, start, bytes, 0, length);
+                return bytes;
+            }
+
+            /**
+             * Parse scan record to {@link BluetoothLeAdvertiseScanData.ScanRecord}.
+             * <p>
+             * The format is defined in Bluetooth 4.0 specification, Volume 3, Part C, Section 11
+             * and 18.
+             * <p>
+             * All numerical multi-byte entities and values shall use little-endian
+             * <strong>byte</strong> order.
+             *
+             * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
+             */
+            public ScanRecord parseFromScanRecord(byte[] scanRecord) {
+                if (scanRecord == null) {
+                    return null;
+                }
+
+                int currentPos = 0;
+                int advertiseFlag = -1;
+                List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
+                String localName = null;
+                int txPowerLevel = Integer.MIN_VALUE;
+                ParcelUuid serviceDataUuid = null;
+                byte[] serviceData = null;
+                int manufacturerId = -1;
+                byte[] manufacturerSpecificData = null;
+
+                try {
+                    while (currentPos < scanRecord.length) {
+                        // length is unsigned int.
+                        int length = scanRecord[currentPos++] & 0xFF;
+                        if (length == 0) {
+                            break;
+                        }
+                        // Note the length includes the length of the field type itself.
+                        int dataLength = length - 1;
+                        // fieldType is unsigned int.
+                        int fieldType = scanRecord[currentPos++] & 0xFF;
+                        switch (fieldType) {
+                            case DATA_TYPE_FLAGS:
+                                advertiseFlag = scanRecord[currentPos] & 0xFF;
+                                break;
+                            case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
+                            case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
+                                parseServiceUuid(scanRecord, currentPos,
+                                        dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
+                                break;
+                            case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
+                            case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
+                                parseServiceUuid(scanRecord, currentPos, dataLength,
+                                        BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
+                                break;
+                            case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
+                            case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
+                                parseServiceUuid(scanRecord, currentPos, dataLength,
+                                        BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
+                                break;
+                            case DATA_TYPE_LOCAL_NAME_SHORT:
+                            case DATA_TYPE_LOCAL_NAME_COMPLETE:
+                                localName = new String(
+                                        extractBytes(scanRecord, currentPos, dataLength));
+                                break;
+                            case DATA_TYPE_TX_POWER_LEVEL:
+                                txPowerLevel = scanRecord[currentPos];
+                                break;
+                            case DATA_TYPE_SERVICE_DATA:
+                                serviceData = extractBytes(scanRecord, currentPos, dataLength);
+                                // The first two bytes of the service data are service data uuid.
+                                int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
+                                byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
+                                        serviceUuidLength);
+                                serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes);
+                                break;
+                            case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
+                                manufacturerSpecificData = extractBytes(scanRecord, currentPos,
+                                        dataLength);
+                                // The first two bytes of the manufacturer specific data are
+                                // manufacturer ids in little endian.
+                                manufacturerId = ((manufacturerSpecificData[1] & 0xFF) << 8) +
+                                        (manufacturerSpecificData[0] & 0xFF);
+                                break;
+                            default:
+                                // Just ignore, we don't handle such data type.
+                                break;
+                        }
+                        currentPos += dataLength;
+                    }
+
+                    if (serviceUuids.isEmpty()) {
+                        serviceUuids = null;
+                    }
+                    return new ScanRecord(PARSED_SCAN_RECORD,
+                            serviceUuids, serviceDataUuid, serviceData,
+                            manufacturerId, manufacturerSpecificData, advertiseFlag, txPowerLevel,
+                            localName);
+                } catch (IndexOutOfBoundsException e) {
+                    Log.e(PARSER_TAG,
+                            "unable to parse scan record: " + Arrays.toString(scanRecord));
+                    return null;
+                }
+            }
+
+            // Parse service uuids.
+            private int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
+                    int uuidLength, List<ParcelUuid> serviceUuids) {
+                while (dataLength > 0) {
+                    byte[] uuidBytes = extractBytes(scanRecord, currentPos,
+                            uuidLength);
+                    serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
+                    dataLength -= uuidLength;
+                    currentPos += uuidLength;
+                }
+                return currentPos;
+            }
+        }
+    }
+
+}
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/bluetooth/BluetoothLeAdvertiser.aidl
similarity index 73%
copy from core/java/android/service/notification/NotificationOrderUpdate.aidl
copy to core/java/android/bluetooth/BluetoothLeAdvertiser.aidl
index 5d50641..3108610 100644
--- a/core/java/android/service/notification/NotificationOrderUpdate.aidl
+++ b/core/java/android/bluetooth/BluetoothLeAdvertiser.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.notification;
+package android.bluetooth;
 
-parcelable NotificationOrderUpdate;
+parcelable BluetoothLeAdvertiser.Settings;
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/BluetoothLeAdvertiser.java
new file mode 100644
index 0000000..2a8aa23
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeAdvertiser.java
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * This class provides a way to perform Bluetooth LE advertise operations, such as start and stop
+ * advertising. An advertiser can broadcast up to 31 bytes of advertisement data represented by
+ * {@link BluetoothLeAdvertiseScanData.AdvertisementData}.
+ * <p>
+ * To get an instance of {@link BluetoothLeAdvertiser}, call the
+ * {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method.
+ * <p>
+ * Note most of the methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @see BluetoothLeAdvertiseScanData.AdvertisementData
+ */
+public class BluetoothLeAdvertiser {
+
+    private static final String TAG = "BluetoothLeAdvertiser";
+
+    /**
+     * The {@link Settings} provide a way to adjust advertising preferences for each individual
+     * advertisement. Use {@link Settings.Builder} to create a {@link Settings} instance.
+     */
+    public static final class Settings implements Parcelable {
+        /**
+         * Perform Bluetooth LE advertising in low power mode. This is the default and preferred
+         * advertising mode as it consumes the least power.
+         */
+        public static final int ADVERTISE_MODE_LOW_POWER = 0;
+        /**
+         * Perform Bluetooth LE advertising in balanced power mode. This is balanced between
+         * advertising frequency and power consumption.
+         */
+        public static final int ADVERTISE_MODE_BALANCED = 1;
+        /**
+         * Perform Bluetooth LE advertising in low latency, high power mode. This has the highest
+         * power consumption and should not be used for background continuous advertising.
+         */
+        public static final int ADVERTISE_MODE_LOW_LATENCY = 2;
+
+        /**
+         * Advertise using the lowest transmission(tx) power level. An app can use low transmission
+         * power to restrict the visibility range of its advertising packet.
+         */
+        public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0;
+        /**
+         * Advertise using low tx power level.
+         */
+        public static final int ADVERTISE_TX_POWER_LOW = 1;
+        /**
+         * Advertise using medium tx power level.
+         */
+        public static final int ADVERTISE_TX_POWER_MEDIUM = 2;
+        /**
+         * Advertise using high tx power level. This is corresponding to largest visibility range of
+         * the advertising packet.
+         */
+        public static final int ADVERTISE_TX_POWER_HIGH = 3;
+
+        /**
+         * Non-connectable undirected advertising event, as defined in Bluetooth Specification V4.0
+         * vol6, part B, section 4.4.2 - Advertising state.
+         */
+        public static final int ADVERTISE_TYPE_NON_CONNECTABLE = 0;
+        /**
+         * Scannable undirected advertise type, as defined in same spec mentioned above. This event
+         * type allows a scanner to send a scan request asking additional information about the
+         * advertiser.
+         */
+        public static final int ADVERTISE_TYPE_SCANNABLE = 1;
+        /**
+         * Connectable undirected advertising type, as defined in same spec mentioned above. This
+         * event type allows a scanner to send scan request asking additional information about the
+         * advertiser. It also allows an initiator to send a connect request for connection.
+         */
+        public static final int ADVERTISE_TYPE_CONNECTABLE = 2;
+
+        private final int mAdvertiseMode;
+        private final int mAdvertiseTxPowerLevel;
+        private final int mAdvertiseEventType;
+
+        private Settings(int advertiseMode, int advertiseTxPowerLevel,
+                int advertiseEventType) {
+            mAdvertiseMode = advertiseMode;
+            mAdvertiseTxPowerLevel = advertiseTxPowerLevel;
+            mAdvertiseEventType = advertiseEventType;
+        }
+
+        private Settings(Parcel in) {
+            mAdvertiseMode = in.readInt();
+            mAdvertiseTxPowerLevel = in.readInt();
+            mAdvertiseEventType = in.readInt();
+        }
+
+        /**
+         * Creates a {@link Builder} to construct a {@link Settings} object.
+         */
+        public static Builder newBuilder() {
+            return new Builder();
+        }
+
+        /**
+         * Returns the advertise mode.
+         */
+        public int getMode() {
+            return mAdvertiseMode;
+        }
+
+        /**
+         * Returns the tx power level for advertising.
+         */
+        public int getTxPowerLevel() {
+            return mAdvertiseTxPowerLevel;
+        }
+
+        /**
+         * Returns the advertise event type.
+         */
+        public int getType() {
+            return mAdvertiseEventType;
+        }
+
+        @Override
+        public String toString() {
+            return "Settings [mAdvertiseMode=" + mAdvertiseMode + ", mAdvertiseTxPowerLevel="
+                    + mAdvertiseTxPowerLevel + ", mAdvertiseEventType=" + mAdvertiseEventType + "]";
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mAdvertiseMode);
+            dest.writeInt(mAdvertiseTxPowerLevel);
+            dest.writeInt(mAdvertiseEventType);
+        }
+
+        public static final Parcelable.Creator<Settings> CREATOR =
+                new Creator<BluetoothLeAdvertiser.Settings>() {
+                @Override
+                    public Settings[] newArray(int size) {
+                        return new Settings[size];
+                    }
+
+                @Override
+                    public Settings createFromParcel(Parcel in) {
+                        return new Settings(in);
+                    }
+                };
+
+        /**
+         * Builder class for {@link BluetoothLeAdvertiser.Settings}. Caller should use
+         * {@link Settings#newBuilder()} to get an instance of the builder.
+         */
+        public static final class Builder {
+            private int mMode = ADVERTISE_MODE_LOW_POWER;
+            private int mTxPowerLevel = ADVERTISE_TX_POWER_MEDIUM;
+            private int mType = ADVERTISE_TYPE_NON_CONNECTABLE;
+
+            // Private constructor, use Settings.newBuilder() get an instance of BUILDER.
+            private Builder() {
+            }
+
+            /**
+             * Set advertise mode to control the advertising power and latency.
+             *
+             * @param advertiseMode Bluetooth LE Advertising mode, can only be one of
+             *            {@link Settings#ADVERTISE_MODE_LOW_POWER},
+             *            {@link Settings#ADVERTISE_MODE_BALANCED}, or
+             *            {@link Settings#ADVERTISE_MODE_LOW_LATENCY}.
+             * @throws IllegalArgumentException If the advertiseMode is invalid.
+             */
+            public Builder advertiseMode(int advertiseMode) {
+                if (advertiseMode < ADVERTISE_MODE_LOW_POWER
+                        || advertiseMode > ADVERTISE_MODE_LOW_LATENCY) {
+                    throw new IllegalArgumentException("unknown mode " + advertiseMode);
+                }
+                mMode = advertiseMode;
+                return this;
+            }
+
+            /**
+             * Set advertise tx power level to control the transmission power level for the
+             * advertising.
+             *
+             * @param txPowerLevel Transmission power of Bluetooth LE Advertising, can only be one
+             *            of {@link Settings#ADVERTISE_TX_POWER_ULTRA_LOW},
+             *            {@link Settings#ADVERTISE_TX_POWER_LOW},
+             *            {@link Settings#ADVERTISE_TX_POWER_MEDIUM} or
+             *            {@link Settings#ADVERTISE_TX_POWER_HIGH}.
+             * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid.
+             */
+            public Builder txPowerLevel(int txPowerLevel) {
+                if (txPowerLevel < ADVERTISE_TX_POWER_ULTRA_LOW
+                        || txPowerLevel > ADVERTISE_TX_POWER_HIGH) {
+                    throw new IllegalArgumentException("unknown tx power level " + txPowerLevel);
+                }
+                mTxPowerLevel = txPowerLevel;
+                return this;
+            }
+
+            /**
+             * Set advertise type to control the event type of advertising.
+             *
+             * @param type Bluetooth LE Advertising type, can be either
+             *            {@link Settings#ADVERTISE_TYPE_NON_CONNECTABLE},
+             *            {@link Settings#ADVERTISE_TYPE_SCANNABLE} or
+             *            {@link Settings#ADVERTISE_TYPE_CONNECTABLE}.
+             * @throws IllegalArgumentException If the {@code type} is invalid.
+             */
+            public Builder type(int type) {
+                if (type < ADVERTISE_TYPE_NON_CONNECTABLE
+                        || type > ADVERTISE_TYPE_CONNECTABLE) {
+                    throw new IllegalArgumentException("unknown advertise type " + type);
+                }
+                mType = type;
+                return this;
+            }
+
+            /**
+             * Build the {@link Settings} object.
+             */
+            public Settings build() {
+                return new Settings(mMode, mTxPowerLevel, mType);
+            }
+        }
+    }
+
+    /**
+     * Callback of Bluetooth LE advertising, which is used to deliver operation status for start and
+     * stop advertising.
+     */
+    public interface AdvertiseCallback {
+
+        /**
+         * The operation is success.
+         *
+         * @hide
+         */
+        public static final int SUCCESS = 0;
+        /**
+         * Fails to start advertising as the advertisement data contains services that are not added
+         * to the local bluetooth Gatt server.
+         */
+        public static final int ADVERTISING_SERVICE_UNKNOWN = 1;
+        /**
+         * Fails to start advertising as system runs out of quota for advertisers.
+         */
+        public static final int TOO_MANY_ADVERTISERS = 2;
+
+        /**
+         * Fails to start advertising as the advertising is already started.
+         */
+        public static final int ADVERTISING_ALREADY_STARTED = 3;
+        /**
+         * Fails to stop advertising as the advertising is not started.
+         */
+        public static final int ADVERISING_NOT_STARTED = 4;
+
+        /**
+         * Operation fails due to bluetooth controller failure.
+         */
+        public static final int CONTROLLER_FAILURE = 5;
+
+        /**
+         * Callback when advertising operation succeeds.
+         *
+         * @param settingsInEffect The actual settings used for advertising, which may be different
+         *            from what the app asks.
+         */
+        public void onSuccess(Settings settingsInEffect);
+
+        /**
+         * Callback when advertising operation fails.
+         *
+         * @param errorCode Error code for failures.
+         */
+        public void onFailure(int errorCode);
+    }
+
+    private final IBluetoothGatt mBluetoothGatt;
+    private final Handler mHandler;
+    private final Map<Settings, AdvertiseCallbackWrapper>
+            mLeAdvertisers = new HashMap<Settings, AdvertiseCallbackWrapper>();
+
+    // Package private constructor, use BluetoothAdapter.getLeAdvertiser() instead.
+    BluetoothLeAdvertiser(IBluetoothGatt bluetoothGatt) {
+        mBluetoothGatt = bluetoothGatt;
+        mHandler = new Handler(Looper.getMainLooper());
+    }
+
+    /**
+     * Bluetooth GATT interface callbacks for advertising.
+     */
+    private static class AdvertiseCallbackWrapper extends IBluetoothGattCallback.Stub {
+        private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
+        private final AdvertiseCallback mAdvertiseCallback;
+        private final AdvertisementData mAdvertisement;
+        private final Settings mSettings;
+        private final IBluetoothGatt mBluetoothGatt;
+
+        // mLeHandle 0: not registered
+        // -1: scan stopped
+        // >0: registered and scan started
+        private int mLeHandle;
+        private boolean isAdvertising = false;
+
+        public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
+                AdvertisementData advertiseData, Settings settings,
+                IBluetoothGatt bluetoothGatt) {
+            mAdvertiseCallback = advertiseCallback;
+            mAdvertisement = advertiseData;
+            mSettings = settings;
+            mBluetoothGatt = bluetoothGatt;
+            mLeHandle = 0;
+        }
+
+        public boolean advertiseStarted() {
+            boolean started = false;
+            synchronized (this) {
+                if (mLeHandle == -1) {
+                    return false;
+                }
+                try {
+                    wait(LE_CALLBACK_TIMEOUT_MILLIS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Callback reg wait interrupted: " + e);
+                }
+                started = (mLeHandle > 0 && isAdvertising);
+            }
+            return started;
+        }
+
+        public boolean advertiseStopped() {
+            synchronized (this) {
+                try {
+                    wait(LE_CALLBACK_TIMEOUT_MILLIS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Callback reg wait interrupted: " + e);
+                }
+                return !isAdvertising;
+            }
+        }
+
+        /**
+         * Application interface registered - app is ready to go
+         */
+        @Override
+        public void onClientRegistered(int status, int clientIf) {
+            Log.d(TAG, "onClientRegistered() - status=" + status + " clientIf=" + clientIf);
+            synchronized (this) {
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    mLeHandle = clientIf;
+                    try {
+                        mBluetoothGatt.startMultiAdvertising(mLeHandle, mAdvertisement, mSettings);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "fail to start le advertise: " + e);
+                        mLeHandle = -1;
+                        notifyAll();
+                    } catch (Exception e) {
+                        Log.e(TAG, "fail to start advertise: " + e.getStackTrace());
+                    }
+                } else {
+                    // registration failed
+                    mLeHandle = -1;
+                    notifyAll();
+                }
+            }
+        }
+
+        @Override
+        public void onClientConnectionState(int status, int clientIf,
+                boolean connected, String address) {
+            // no op
+        }
+
+        @Override
+        public void onScanResult(String address, int rssi, byte[] advData) {
+            // no op
+        }
+
+        @Override
+        public void onGetService(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid) {
+            // no op
+        }
+
+        @Override
+        public void onGetIncludedService(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int inclSrvcType, int inclSrvcInstId,
+                ParcelUuid inclSrvcUuid) {
+            // no op
+        }
+
+        @Override
+        public void onGetCharacteristic(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int charProps) {
+            // no op
+        }
+
+        @Override
+        public void onGetDescriptor(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descUuid) {
+            // no op
+        }
+
+        @Override
+        public void onSearchComplete(String address, int status) {
+            // no op
+        }
+
+        @Override
+        public void onCharacteristicRead(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid, byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onCharacteristicWrite(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid) {
+            // no op
+        }
+
+        @Override
+        public void onNotify(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onDescriptorRead(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descrUuid, byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onDescriptorWrite(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descrUuid) {
+            // no op
+        }
+
+        @Override
+        public void onExecuteWrite(String address, int status) {
+            // no op
+        }
+
+        @Override
+        public void onReadRemoteRssi(String address, int rssi, int status) {
+            // no op
+        }
+
+        @Override
+        public void onAdvertiseStateChange(int advertiseState, int status) {
+            // no op
+        }
+
+        @Override
+        public void onMultiAdvertiseCallback(int status) {
+            synchronized (this) {
+                if (status == 0) {
+                    isAdvertising = !isAdvertising;
+                    if (!isAdvertising) {
+                        try {
+                            mBluetoothGatt.unregisterClient(mLeHandle);
+                            mLeHandle = -1;
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "remote exception when unregistering", e);
+                        }
+                    }
+                    mAdvertiseCallback.onSuccess(null);
+                } else {
+                    mAdvertiseCallback.onFailure(status);
+                }
+                notifyAll();
+            }
+
+        }
+
+        /**
+         * Callback reporting LE ATT MTU.
+         *
+         * @hide
+         */
+        public void onConfigureMTU(String address, int mtu, int status) {
+            // no op
+        }
+    }
+
+    /**
+     * Start Bluetooth LE Advertising.
+     *
+     * @param settings {@link Settings} for Bluetooth LE advertising.
+     * @param advertiseData {@link AdvertisementData} to be advertised.
+     * @param callback {@link AdvertiseCallback} for advertising status.
+     */
+    public void startAdvertising(Settings settings,
+            AdvertisementData advertiseData, final AdvertiseCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        if (mLeAdvertisers.containsKey(settings)) {
+            postCallbackFailure(callback, AdvertiseCallback.ADVERTISING_ALREADY_STARTED);
+            return;
+        }
+        AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
+                settings,
+                mBluetoothGatt);
+        UUID uuid = UUID.randomUUID();
+        try {
+            mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+            if (wrapper.advertiseStarted()) {
+                mLeAdvertisers.put(settings, wrapper);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to stop advertising", e);
+        }
+    }
+
+    /**
+     * Stop Bluetooth LE advertising. Returns immediately, the operation status will be delivered
+     * through the {@code callback}.
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     *
+     * @param settings {@link Settings} used to start Bluetooth LE advertising.
+     * @param callback {@link AdvertiseCallback} for delivering stopping advertising status.
+     */
+    public void stopAdvertising(final Settings settings, final AdvertiseCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(settings);
+        if (wrapper == null) {
+            postCallbackFailure(callback, AdvertiseCallback.ADVERISING_NOT_STARTED);
+            return;
+        }
+        try {
+            mBluetoothGatt.stopMultiAdvertising(wrapper.mLeHandle);
+            if (wrapper.advertiseStopped()) {
+                mLeAdvertisers.remove(settings);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to stop advertising", e);
+        }
+    }
+
+    private void postCallbackFailure(final AdvertiseCallback callback, final int error) {
+        mHandler.post(new Runnable() {
+                @Override
+            public void run() {
+                callback.onFailure(error);
+            }
+        });
+    }
+}
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/bluetooth/BluetoothLeScanFilter.aidl
similarity index 73%
copy from core/java/android/service/notification/NotificationOrderUpdate.aidl
copy to core/java/android/bluetooth/BluetoothLeScanFilter.aidl
index 5d50641..86ee06d 100644
--- a/core/java/android/service/notification/NotificationOrderUpdate.aidl
+++ b/core/java/android/bluetooth/BluetoothLeScanFilter.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.notification;
+package android.bluetooth;
 
-parcelable NotificationOrderUpdate;
+parcelable BluetoothLeScanFilter;
diff --git a/core/java/android/bluetooth/BluetoothLeScanFilter.java b/core/java/android/bluetooth/BluetoothLeScanFilter.java
new file mode 100644
index 0000000..2ed85ba
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeScanFilter.java
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothLeAdvertiseScanData.ScanRecord;
+import android.bluetooth.BluetoothLeScanner.ScanResult;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * {@link BluetoothLeScanFilter} abstracts different scan filters across Bluetooth Advertisement
+ * packet fields.
+ * <p>
+ * Current filtering on the following fields are supported:
+ * <li>Service UUIDs which identify the bluetooth gatt services running on the device.
+ * <li>Name of remote Bluetooth LE device.
+ * <li>Mac address of the remote device.
+ * <li>Rssi which indicates the received power level.
+ * <li>Service data which is the data associated with a service.
+ * <li>Manufacturer specific data which is the data associated with a particular manufacturer.
+ *
+ * @see BluetoothLeAdvertiseScanData.ScanRecord
+ * @see BluetoothLeScanner
+ */
+public final class BluetoothLeScanFilter implements Parcelable {
+
+    @Nullable
+    private final String mLocalName;
+
+    @Nullable
+    private final String mMacAddress;
+
+    @Nullable
+    private final ParcelUuid mServiceUuid;
+    @Nullable
+    private final ParcelUuid mServiceUuidMask;
+
+    @Nullable
+    private final byte[] mServiceData;
+    @Nullable
+    private final byte[] mServiceDataMask;
+
+    private final int mManufacturerId;
+    @Nullable
+    private final byte[] mManufacturerData;
+    @Nullable
+    private final byte[] mManufacturerDataMask;
+
+    private final int mMinRssi;
+    private final int mMaxRssi;
+
+    private BluetoothLeScanFilter(String name, String macAddress, ParcelUuid uuid,
+            ParcelUuid uuidMask, byte[] serviceData, byte[] serviceDataMask,
+            int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
+            int minRssi, int maxRssi) {
+        mLocalName = name;
+        mServiceUuid = uuid;
+        mServiceUuidMask = uuidMask;
+        mMacAddress = macAddress;
+        mServiceData = serviceData;
+        mServiceDataMask = serviceDataMask;
+        mManufacturerId = manufacturerId;
+        mManufacturerData = manufacturerData;
+        mManufacturerDataMask = manufacturerDataMask;
+        mMinRssi = minRssi;
+        mMaxRssi = maxRssi;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mLocalName == null ? 0 : 1);
+        if (mLocalName != null) {
+            dest.writeString(mLocalName);
+        }
+        dest.writeInt(mMacAddress == null ? 0 : 1);
+        if (mMacAddress != null) {
+            dest.writeString(mMacAddress);
+        }
+        dest.writeInt(mServiceUuid == null ? 0 : 1);
+        if (mServiceUuid != null) {
+            dest.writeParcelable(mServiceUuid, flags);
+        }
+        dest.writeInt(mServiceUuidMask == null ? 0 : 1);
+        if (mServiceUuidMask != null) {
+            dest.writeParcelable(mServiceUuidMask, flags);
+        }
+        dest.writeInt(mServiceData == null ? 0 : mServiceData.length);
+        if (mServiceData != null) {
+            dest.writeByteArray(mServiceData);
+        }
+        dest.writeInt(mServiceDataMask == null ? 0 : mServiceDataMask.length);
+        if (mServiceDataMask != null) {
+            dest.writeByteArray(mServiceDataMask);
+        }
+        dest.writeInt(mManufacturerId);
+        dest.writeInt(mManufacturerData == null ? 0 : mManufacturerData.length);
+        if (mManufacturerData != null) {
+            dest.writeByteArray(mManufacturerData);
+        }
+        dest.writeInt(mManufacturerDataMask == null ? 0 : mManufacturerDataMask.length);
+        if (mManufacturerDataMask != null) {
+            dest.writeByteArray(mManufacturerDataMask);
+        }
+        dest.writeInt(mMinRssi);
+        dest.writeInt(mMaxRssi);
+    }
+
+    /**
+     * A {@link android.os.Parcelable.Creator} to create {@link BluetoothLeScanFilter} form parcel.
+     */
+    public static final Creator<BluetoothLeScanFilter>
+            CREATOR = new Creator<BluetoothLeScanFilter>() {
+
+                    @Override
+                public BluetoothLeScanFilter[] newArray(int size) {
+                    return new BluetoothLeScanFilter[size];
+                }
+
+                    @Override
+                public BluetoothLeScanFilter createFromParcel(Parcel in) {
+                    Builder builder = newBuilder();
+                    if (in.readInt() == 1) {
+                        builder.name(in.readString());
+                    }
+                    if (in.readInt() == 1) {
+                        builder.macAddress(in.readString());
+                    }
+                    if (in.readInt() == 1) {
+                        ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
+                        builder.serviceUuid(uuid);
+                    }
+                    if (in.readInt() == 1) {
+                        ParcelUuid uuidMask = in.readParcelable(ParcelUuid.class.getClassLoader());
+                        builder.serviceUuidMask(uuidMask);
+                    }
+                    int serviceDataLength = in.readInt();
+                    if (serviceDataLength > 0) {
+                        byte[] serviceData = new byte[serviceDataLength];
+                        in.readByteArray(serviceData);
+                        builder.serviceData(serviceData);
+                    }
+                    int serviceDataMaskLength = in.readInt();
+                    if (serviceDataMaskLength > 0) {
+                        byte[] serviceDataMask = new byte[serviceDataMaskLength];
+                        in.readByteArray(serviceDataMask);
+                        builder.serviceDataMask(serviceDataMask);
+                    }
+                    int manufacturerId = in.readInt();
+                    int manufacturerDataLength = in.readInt();
+                    if (manufacturerDataLength > 0) {
+                        byte[] manufacturerData = new byte[manufacturerDataLength];
+                        in.readByteArray(manufacturerData);
+                        builder.manufacturerData(manufacturerId, manufacturerData);
+                    }
+                    int manufacturerDataMaskLength = in.readInt();
+                    if (manufacturerDataMaskLength > 0) {
+                        byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength];
+                        in.readByteArray(manufacturerDataMask);
+                        builder.manufacturerDataMask(manufacturerDataMask);
+                    }
+                    int minRssi = in.readInt();
+                    int maxRssi = in.readInt();
+                    builder.rssiRange(minRssi, maxRssi);
+                    return builder.build();
+                }
+            };
+
+    /**
+     * Returns the filter set the local name field of Bluetooth advertisement data.
+     */
+    @Nullable
+    public String getLocalName() {
+        return mLocalName;
+    }
+
+    @Nullable /**
+               * Returns the filter set on the service uuid.
+               */
+    public ParcelUuid getServiceUuid() {
+        return mServiceUuid;
+    }
+
+    @Nullable
+    public ParcelUuid getServiceUuidMask() {
+        return mServiceUuidMask;
+    }
+
+    @Nullable
+    public String getDeviceAddress() {
+        return mMacAddress;
+    }
+
+    @Nullable
+    public byte[] getServiceData() {
+        return mServiceData;
+    }
+
+    @Nullable
+    public byte[] getServiceDataMask() {
+        return mServiceDataMask;
+    }
+
+    /**
+     * Returns the manufacturer id. -1 if the manufacturer filter is not set.
+     */
+    public int getManufacturerId() {
+        return mManufacturerId;
+    }
+
+    @Nullable
+    public byte[] getManufacturerData() {
+        return mManufacturerData;
+    }
+
+    @Nullable
+    public byte[] getManufacturerDataMask() {
+        return mManufacturerDataMask;
+    }
+
+    /**
+     * Returns minimum value of rssi for the scan filter. {@link Integer#MIN_VALUE} if not set.
+     */
+    public int getMinRssi() {
+        return mMinRssi;
+    }
+
+    /**
+     * Returns maximum value of the rssi for the scan filter. {@link Integer#MAX_VALUE} if not set.
+     */
+    public int getMaxRssi() {
+        return mMaxRssi;
+    }
+
+    /**
+     * Check if the scan filter matches a {@code scanResult}. A scan result is considered as a match
+     * if it matches all the field filters.
+     */
+    public boolean matches(ScanResult scanResult) {
+        if (scanResult == null) {
+            return false;
+        }
+        BluetoothDevice device = scanResult.getDevice();
+        // Device match.
+        if (mMacAddress != null && (device == null || !mMacAddress.equals(device.getAddress()))) {
+            return false;
+        }
+
+        int rssi = scanResult.getRssi();
+        if (rssi < mMinRssi || rssi > mMaxRssi) {
+            return false;
+        }
+
+        byte[] scanRecordBytes = scanResult.getScanRecord();
+        ScanRecord scanRecord = ScanRecord.getParser().parseFromScanRecord(scanRecordBytes);
+
+        // Scan record is null but there exist filters on it.
+        if (scanRecord == null
+                && (mLocalName != null || mServiceUuid != null || mManufacturerData != null
+                        || mServiceData != null)) {
+            return false;
+        }
+
+        // Local name match.
+        if (mLocalName != null && !mLocalName.equals(scanRecord.getLocalName())) {
+            return false;
+        }
+
+        // UUID match.
+        if (mServiceUuid != null && !matchesServiceUuids(mServiceUuid, mServiceUuidMask,
+                scanRecord.getServiceUuids())) {
+            return false;
+        }
+
+        // Service data match
+        if (mServiceData != null &&
+                !matchesPartialData(mServiceData, mServiceDataMask, scanRecord.getServiceData())) {
+            return false;
+        }
+
+        // Manufacturer data match.
+        if (mManufacturerData != null && !matchesPartialData(mManufacturerData,
+                mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) {
+            return false;
+        }
+        // All filters match.
+        return true;
+    }
+
+    // Check if the uuid pattern is contained in a list of parcel uuids.
+    private boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
+            List<ParcelUuid> uuids) {
+        if (uuid == null) {
+            return true;
+        }
+        if (uuids == null) {
+            return false;
+        }
+
+        for (ParcelUuid parcelUuid : uuids) {
+            UUID uuidMask = parcelUuidMask == null ? null : parcelUuidMask.getUuid();
+            if (matchesServiceUuid(uuid.getUuid(), uuidMask, parcelUuid.getUuid())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Check if the uuid pattern matches the particular service uuid.
+    private boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
+        if (mask == null) {
+            return uuid.equals(data);
+        }
+        if ((uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) !=
+                (data.getLeastSignificantBits() & mask.getLeastSignificantBits())) {
+            return false;
+        }
+        return ((uuid.getMostSignificantBits() & mask.getMostSignificantBits()) ==
+                (data.getMostSignificantBits() & mask.getMostSignificantBits()));
+    }
+
+    // Check whether the data pattern matches the parsed data.
+    private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) {
+        if (dataMask == null) {
+            return Arrays.equals(data, parsedData);
+        }
+        if (parsedData == null) {
+            return false;
+        }
+        for (int i = 0; i < data.length; ++i) {
+            if ((dataMask[i] & parsedData[i]) != (dataMask[i] & data[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "BluetoothLeScanFilter [mLocalName=" + mLocalName + ", mMacAddress=" + mMacAddress
+                + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + ", mServiceData="
+                + Arrays.toString(mServiceData) + ", mServiceDataMask="
+                + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId
+                + ", mManufacturerData=" + Arrays.toString(mManufacturerData)
+                + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask)
+                + ", mMinRssi=" + mMinRssi + ", mMaxRssi=" + mMaxRssi + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLocalName, mMacAddress, mManufacturerId, mManufacturerData,
+                mManufacturerDataMask, mMaxRssi, mMinRssi, mServiceData, mServiceDataMask,
+                mServiceUuid, mServiceUuidMask);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        BluetoothLeScanFilter other = (BluetoothLeScanFilter) obj;
+        return Objects.equals(mLocalName, other.mLocalName) &&
+                Objects.equals(mMacAddress, other.mMacAddress) &&
+                mManufacturerId == other.mManufacturerId &&
+                Objects.deepEquals(mManufacturerData, other.mManufacturerData) &&
+                Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) &&
+                mMinRssi == other.mMinRssi && mMaxRssi == other.mMaxRssi &&
+                Objects.deepEquals(mServiceData, other.mServiceData) &&
+                Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) &&
+                Objects.equals(mServiceUuid, other.mServiceUuid) &&
+                Objects.equals(mServiceUuidMask, other.mServiceUuidMask);
+    }
+
+    /**
+     * Returns the {@link Builder} for {@link BluetoothLeScanFilter}.
+     */
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder class for {@link BluetoothLeScanFilter}. Use
+     * {@link BluetoothLeScanFilter#newBuilder()} to get an instance of the {@link Builder}.
+     */
+    public static class Builder {
+
+        private String mLocalName;
+        private String mMacAddress;
+
+        private ParcelUuid mServiceUuid;
+        private ParcelUuid mUuidMask;
+
+        private byte[] mServiceData;
+        private byte[] mServiceDataMask;
+
+        private int mManufacturerId = -1;
+        private byte[] mManufacturerData;
+        private byte[] mManufacturerDataMask;
+
+        private int mMinRssi = Integer.MIN_VALUE;
+        private int mMaxRssi = Integer.MAX_VALUE;
+
+        // Private constructor, use BluetoothLeScanFilter.newBuilder instead.
+        private Builder() {
+        }
+
+        /**
+         * Set filtering on local name.
+         */
+        public Builder name(String localName) {
+            mLocalName = localName;
+            return this;
+        }
+
+        /**
+         * Set filtering on device mac address.
+         *
+         * @param macAddress The device mac address for the filter. It needs to be in the format of
+         *            "01:02:03:AB:CD:EF". The mac address can be validated using
+         *            {@link BluetoothAdapter#checkBluetoothAddress}.
+         * @throws IllegalArgumentException If the {@code macAddress} is invalid.
+         */
+        public Builder macAddress(String macAddress) {
+            if (macAddress != null && !BluetoothAdapter.checkBluetoothAddress(macAddress)) {
+                throw new IllegalArgumentException("invalid mac address " + macAddress);
+            }
+            mMacAddress = macAddress;
+            return this;
+        }
+
+        /**
+         * Set filtering on service uuid.
+         */
+        public Builder serviceUuid(ParcelUuid serviceUuid) {
+            mServiceUuid = serviceUuid;
+            return this;
+        }
+
+        /**
+         * Set partial uuid filter. The {@code uuidMask} is the bit mask for the {@code uuid} set
+         * through {@link #serviceUuid(ParcelUuid)} method. Set any bit in the mask to 1 to indicate
+         * a match is needed for the bit in {@code serviceUuid}, and 0 to ignore that bit.
+         * <p>
+         * The length of {@code uuidMask} must be the same as {@code serviceUuid}.
+         */
+        public Builder serviceUuidMask(ParcelUuid uuidMask) {
+            mUuidMask = uuidMask;
+            return this;
+        }
+
+        /**
+         * Set service data filter.
+         */
+        public Builder serviceData(byte[] serviceData) {
+            mServiceData = serviceData;
+            return this;
+        }
+
+        /**
+         * Set partial service data filter bit mask. For any bit in the mask, set it to 1 if it
+         * needs to match the one in service data, otherwise set it to 0 to ignore that bit.
+         * <p>
+         * The {@code serviceDataMask} must have the same length of the {@code serviceData} set
+         * through {@link #serviceData(byte[])}.
+         */
+        public Builder serviceDataMask(byte[] serviceDataMask) {
+            mServiceDataMask = serviceDataMask;
+            return this;
+        }
+
+        /**
+         * Set manufacturerId and manufacturerData. A negative manufacturerId is considered as
+         * invalid id.
+         * <p>
+         * Note the first two bytes of the {@code manufacturerData} is the manufacturerId.
+         */
+        public Builder manufacturerData(int manufacturerId, byte[] manufacturerData) {
+            if (manufacturerData != null && manufacturerId < 0) {
+                throw new IllegalArgumentException("invalid manufacture id");
+            }
+            mManufacturerId = manufacturerId;
+            mManufacturerData = manufacturerData;
+            return this;
+        }
+
+        /**
+         * Set partial manufacture data filter bit mask. For any bit in the mask, set it the 1 if it
+         * needs to match the one in manufacturer data, otherwise set it to 0.
+         * <p>
+         * The {@code manufacturerDataMask} must have the same length of {@code manufacturerData}
+         * set through {@link #manufacturerData(int, byte[])}.
+         */
+        public Builder manufacturerDataMask(byte[] manufacturerDataMask) {
+            mManufacturerDataMask = manufacturerDataMask;
+            return this;
+        }
+
+        /**
+         * Set the desired rssi range for the filter. A scan result with rssi in the range of
+         * [minRssi, maxRssi] will be consider as a match.
+         */
+        public Builder rssiRange(int minRssi, int maxRssi) {
+            mMinRssi = minRssi;
+            mMaxRssi = maxRssi;
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeScanFilter}.
+         *
+         * @throws IllegalArgumentException If the filter cannot be built.
+         */
+        public BluetoothLeScanFilter build() {
+            if (mUuidMask != null && mServiceUuid == null) {
+                throw new IllegalArgumentException("uuid is null while uuidMask is not null!");
+            }
+
+            if (mServiceDataMask != null) {
+                if (mServiceData == null) {
+                    throw new IllegalArgumentException(
+                            "serviceData is null while serviceDataMask is not null");
+                }
+                // Since the mServiceDataMask is a bit mask for mServiceData, the lengths of the two
+                // byte array need to be the same.
+                if (mServiceData.length != mServiceDataMask.length) {
+                    throw new IllegalArgumentException(
+                            "size mismatch for service data and service data mask");
+                }
+            }
+
+            if (mManufacturerDataMask != null) {
+                if (mManufacturerData == null) {
+                    throw new IllegalArgumentException(
+                            "manufacturerData is null while manufacturerDataMask is not null");
+                }
+                // Since the mManufacturerDataMask is a bit mask for mManufacturerData, the lengths
+                // of the two byte array need to be the same.
+                if (mManufacturerData.length != mManufacturerDataMask.length) {
+                    throw new IllegalArgumentException(
+                            "size mismatch for manufacturerData and manufacturerDataMask");
+                }
+            }
+            return new BluetoothLeScanFilter(mLocalName, mMacAddress,
+                    mServiceUuid, mUuidMask,
+                    mServiceData, mServiceDataMask,
+                    mManufacturerId, mManufacturerData, mManufacturerDataMask, mMinRssi, mMaxRssi);
+        }
+    }
+}
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/bluetooth/BluetoothLeScanner.aidl
similarity index 69%
copy from core/java/android/service/notification/NotificationOrderUpdate.aidl
copy to core/java/android/bluetooth/BluetoothLeScanner.aidl
index 5d50641..8cecdd7 100644
--- a/core/java/android/service/notification/NotificationOrderUpdate.aidl
+++ b/core/java/android/bluetooth/BluetoothLeScanner.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.notification;
+package android.bluetooth;
 
-parcelable NotificationOrderUpdate;
+parcelable BluetoothLeScanner.ScanResult;
+parcelable BluetoothLeScanner.Settings;
diff --git a/core/java/android/bluetooth/BluetoothLeScanner.java b/core/java/android/bluetooth/BluetoothLeScanner.java
new file mode 100644
index 0000000..ed3188b
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeScanner.java
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class provides methods to perform scan related operations for Bluetooth LE devices. An
+ * application can scan for a particular type of BLE devices using {@link BluetoothLeScanFilter}. It
+ * can also request different types of callbacks for delivering the result.
+ * <p>
+ * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
+ * {@link BluetoothLeScanner}.
+ * <p>
+ * Note most of the scan methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @see BluetoothLeScanFilter
+ */
+public class BluetoothLeScanner {
+
+    private static final String TAG = "BluetoothLeScanner";
+    private static final boolean DBG = true;
+
+    /**
+     * Settings for Bluetooth LE scan.
+     */
+    public static final class Settings implements Parcelable {
+        /**
+         * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes
+         * the least power.
+         */
+        public static final int SCAN_MODE_LOW_POWER = 0;
+        /**
+         * Perform Bluetooth LE scan in balanced power mode.
+         */
+        public static final int SCAN_MODE_BALANCED = 1;
+        /**
+         * Scan using highest duty cycle. It's recommended only using this mode when the application
+         * is running in foreground.
+         */
+        public static final int SCAN_MODE_LOW_LATENCY = 2;
+
+        /**
+         * Callback each time when a bluetooth advertisement is found.
+         */
+        public static final int CALLBACK_TYPE_ON_UPDATE = 0;
+        /**
+         * Callback when a bluetooth advertisement is found for the first time.
+         */
+        public static final int CALLBACK_TYPE_ON_FOUND = 1;
+        /**
+         * Callback when a bluetooth advertisement is found for the first time, then lost.
+         */
+        public static final int CALLBACK_TYPE_ON_LOST = 2;
+
+        /**
+         * Full scan result which contains device mac address, rssi, advertising and scan response
+         * and scan timestamp.
+         */
+        public static final int SCAN_RESULT_TYPE_FULL = 0;
+        /**
+         * Truncated scan result which contains device mac address, rssi and scan timestamp. Note
+         * it's possible for an app to get more scan results that it asks if there are multiple apps
+         * using this type. TODO: decide whether we could unhide this setting.
+         *
+         * @hide
+         */
+        public static final int SCAN_RESULT_TYPE_TRUNCATED = 1;
+
+        // Bluetooth LE scan mode.
+        private int mScanMode;
+
+        // Bluetooth LE scan callback type
+        private int mCallbackType;
+
+        // Bluetooth LE scan result type
+        private int mScanResultType;
+
+        // Time of delay for reporting the scan result
+        private long mReportDelayMicros;
+
+        public int getScanMode() {
+            return mScanMode;
+        }
+
+        public int getCallbackType() {
+            return mCallbackType;
+        }
+
+        public int getScanResultType() {
+            return mScanResultType;
+        }
+
+        /**
+         * Returns report delay timestamp based on the device clock.
+         */
+        public long getReportDelayMicros() {
+            return mReportDelayMicros;
+        }
+
+        /**
+         * Creates a new {@link Builder} to build {@link Settings} object.
+         */
+        public static Builder newBuilder() {
+            return new Builder();
+        }
+
+        private Settings(int scanMode, int callbackType, int scanResultType,
+                long reportDelayMicros) {
+            mScanMode = scanMode;
+            mCallbackType = callbackType;
+            mScanResultType = scanResultType;
+            mReportDelayMicros = reportDelayMicros;
+        }
+
+        private Settings(Parcel in) {
+            mScanMode = in.readInt();
+            mCallbackType = in.readInt();
+            mScanResultType = in.readInt();
+            mReportDelayMicros = in.readLong();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mScanMode);
+            dest.writeInt(mCallbackType);
+            dest.writeInt(mScanResultType);
+            dest.writeLong(mReportDelayMicros);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<Settings> CREATOR = new Creator<Settings>() {
+                @Override
+            public Settings[] newArray(int size) {
+                return new Settings[size];
+            }
+
+                @Override
+            public Settings createFromParcel(Parcel in) {
+                return new Settings(in);
+            }
+        };
+
+        /**
+         * Builder for {@link BluetoothLeScanner.Settings}.
+         */
+        public static class Builder {
+            private int mScanMode = SCAN_MODE_LOW_POWER;
+            private int mCallbackType = CALLBACK_TYPE_ON_UPDATE;
+            private int mScanResultType = SCAN_RESULT_TYPE_FULL;
+            private long mReportDelayMicros = 0;
+
+            // Hidden constructor.
+            private Builder() {
+            }
+
+            /**
+             * Set scan mode for Bluetooth LE scan.
+             *
+             * @param scanMode The scan mode can be one of {@link Settings#SCAN_MODE_LOW_POWER},
+             *            {@link Settings#SCAN_MODE_BALANCED} or
+             *            {@link Settings#SCAN_MODE_LOW_LATENCY}.
+             * @throws IllegalArgumentException If the {@code scanMode} is invalid.
+             */
+            public Builder scanMode(int scanMode) {
+                if (scanMode < SCAN_MODE_LOW_POWER || scanMode > SCAN_MODE_LOW_LATENCY) {
+                    throw new IllegalArgumentException("invalid scan mode " + scanMode);
+                }
+                mScanMode = scanMode;
+                return this;
+            }
+
+            /**
+             * Set callback type for Bluetooth LE scan.
+             *
+             * @param callbackType The callback type for the scan. Can be either one of
+             *            {@link Settings#CALLBACK_TYPE_ON_UPDATE},
+             *            {@link Settings#CALLBACK_TYPE_ON_FOUND} or
+             *            {@link Settings#CALLBACK_TYPE_ON_LOST}.
+             * @throws IllegalArgumentException If the {@code callbackType} is invalid.
+             */
+            public Builder callbackType(int callbackType) {
+                if (callbackType < CALLBACK_TYPE_ON_UPDATE
+                        || callbackType > CALLBACK_TYPE_ON_LOST) {
+                    throw new IllegalArgumentException("invalid callback type - " + callbackType);
+                }
+                mCallbackType = callbackType;
+                return this;
+            }
+
+            /**
+             * Set scan result type for Bluetooth LE scan.
+             *
+             * @param scanResultType Type for scan result, could be either
+             *            {@link Settings#SCAN_RESULT_TYPE_FULL} or
+             *            {@link Settings#SCAN_RESULT_TYPE_TRUNCATED}.
+             * @throws IllegalArgumentException If the {@code scanResultType} is invalid.
+             * @hide
+             */
+            public Builder scanResultType(int scanResultType) {
+                if (scanResultType < SCAN_RESULT_TYPE_FULL
+                        || scanResultType > SCAN_RESULT_TYPE_TRUNCATED) {
+                    throw new IllegalArgumentException(
+                            "invalid scanResultType - " + scanResultType);
+                }
+                mScanResultType = scanResultType;
+                return this;
+            }
+
+            /**
+             * Set report delay timestamp for Bluetooth LE scan.
+             */
+            public Builder reportDelayMicros(long reportDelayMicros) {
+                mReportDelayMicros = reportDelayMicros;
+                return this;
+            }
+
+            /**
+             * Build {@link Settings}.
+             */
+            public Settings build() {
+                return new Settings(mScanMode, mCallbackType, mScanResultType, mReportDelayMicros);
+            }
+        }
+    }
+
+    /**
+     * ScanResult for Bluetooth LE scan.
+     */
+    public static final class ScanResult implements Parcelable {
+        // Remote bluetooth device.
+        private BluetoothDevice mDevice;
+
+        // Scan record, including advertising data and scan response data.
+        private byte[] mScanRecord;
+
+        // Received signal strength.
+        private int mRssi;
+
+        // Device timestamp when the result was last seen.
+        private long mTimestampMicros;
+
+        // Constructor of scan result.
+        public ScanResult(BluetoothDevice device, byte[] scanRecord, int rssi, long timestampMicros) {
+            mDevice = device;
+            mScanRecord = scanRecord;
+            mRssi = rssi;
+            mTimestampMicros = timestampMicros;
+        }
+
+        private ScanResult(Parcel in) {
+            readFromParcel(in);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            if (mDevice != null) {
+                dest.writeInt(1);
+                mDevice.writeToParcel(dest, flags);
+            } else {
+                dest.writeInt(0);
+            }
+            if (mScanRecord != null) {
+                dest.writeInt(1);
+                dest.writeByteArray(mScanRecord);
+            } else {
+                dest.writeInt(0);
+            }
+            dest.writeInt(mRssi);
+            dest.writeLong(mTimestampMicros);
+        }
+
+        private void readFromParcel(Parcel in) {
+            if (in.readInt() == 1) {
+                mDevice = BluetoothDevice.CREATOR.createFromParcel(in);
+            }
+            if (in.readInt() == 1) {
+                mScanRecord = in.createByteArray();
+            }
+            mRssi = in.readInt();
+            mTimestampMicros = in.readLong();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /**
+         * Returns the remote bluetooth device identified by the bluetooth device address.
+         */
+        @Nullable
+        public BluetoothDevice getDevice() {
+            return mDevice;
+        }
+
+        @Nullable /**
+                   * Returns the scan record, which can be a combination of advertisement and scan response.
+                   */
+        public byte[] getScanRecord() {
+            return mScanRecord;
+        }
+
+        /**
+         * Returns the received signal strength in dBm. The valid range is [-127, 127].
+         */
+        public int getRssi() {
+            return mRssi;
+        }
+
+        /**
+         * Returns timestamp since boot when the scan record was observed.
+         */
+        public long getTimestampMicros() {
+            return mTimestampMicros;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampMicros);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            ScanResult other = (ScanResult) obj;
+            return Objects.equals(mDevice, other.mDevice) && (mRssi == other.mRssi) &&
+                    Objects.deepEquals(mScanRecord, other.mScanRecord)
+                    && (mTimestampMicros == other.mTimestampMicros);
+        }
+
+        @Override
+        public String toString() {
+            return "ScanResult{" + "mDevice=" + mDevice + ", mScanRecord="
+                    + Arrays.toString(mScanRecord) + ", mRssi=" + mRssi + ", mTimestampMicros="
+                    + mTimestampMicros + '}';
+        }
+
+        public static final Parcelable.Creator<ScanResult> CREATOR = new Creator<ScanResult>() {
+                @Override
+            public ScanResult createFromParcel(Parcel source) {
+                return new ScanResult(source);
+            }
+
+                @Override
+            public ScanResult[] newArray(int size) {
+                return new ScanResult[size];
+            }
+        };
+
+    }
+
+    /**
+     * Callback of Bluetooth LE scans. The results of the scans will be delivered through the
+     * callbacks.
+     */
+    public interface ScanCallback {
+        /**
+         * Callback when any BLE beacon is found.
+         *
+         * @param result A Bluetooth LE scan result.
+         */
+        public void onDeviceUpdate(ScanResult result);
+
+        /**
+         * Callback when the BLE beacon is found for the first time.
+         *
+         * @param result The Bluetooth LE scan result when the onFound event is triggered.
+         */
+        public void onDeviceFound(ScanResult result);
+
+        /**
+         * Callback when the BLE device was lost. Note a device has to be "found" before it's lost.
+         *
+         * @param device The Bluetooth device that is lost.
+         */
+        public void onDeviceLost(BluetoothDevice device);
+
+        /**
+         * Callback when batch results are delivered.
+         *
+         * @param results List of scan results that are previously scanned.
+         */
+        public void onBatchScanResults(List<ScanResult> results);
+
+        /**
+         * Fails to start scan as BLE scan with the same settings is already started by the app.
+         */
+        public static final int SCAN_ALREADY_STARTED = 1;
+        /**
+         * Fails to start scan as app cannot be registered.
+         */
+        public static final int APPLICATION_REGISTRATION_FAILED = 2;
+        /**
+         * Fails to start scan due to gatt service failure.
+         */
+        public static final int GATT_SERVICE_FAILURE = 3;
+        /**
+         * Fails to start scan due to controller failure.
+         */
+        public static final int CONTROLLER_FAILURE = 4;
+
+        /**
+         * Callback when scan failed.
+         */
+        public void onScanFailed(int errorCode);
+    }
+
+    private final IBluetoothGatt mBluetoothGatt;
+    private final Handler mHandler;
+    private final Map<Settings, BleScanCallbackWrapper> mLeScanClients;
+
+    BluetoothLeScanner(IBluetoothGatt bluetoothGatt) {
+        mBluetoothGatt = bluetoothGatt;
+        mHandler = new Handler(Looper.getMainLooper());
+        mLeScanClients = new HashMap<Settings, BleScanCallbackWrapper>();
+    }
+
+    /**
+     * Bluetooth GATT interface callbacks
+     */
+    private static class BleScanCallbackWrapper extends IBluetoothGattCallback.Stub {
+        private static final int REGISTRATION_CALLBACK_TIMEOUT_SECONDS = 5;
+
+        private final ScanCallback mScanCallback;
+        private final List<BluetoothLeScanFilter> mFilters;
+        private Settings mSettings;
+        private IBluetoothGatt mBluetoothGatt;
+
+        // mLeHandle 0: not registered
+        // -1: scan stopped
+        // > 0: registered and scan started
+        private int mLeHandle;
+
+        public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
+                List<BluetoothLeScanFilter> filters, Settings settings, ScanCallback scanCallback) {
+            mBluetoothGatt = bluetoothGatt;
+            mFilters = filters;
+            mSettings = settings;
+            mScanCallback = scanCallback;
+            mLeHandle = 0;
+        }
+
+        public boolean scanStarted() {
+            synchronized (this) {
+                if (mLeHandle == -1) {
+                    return false;
+                }
+                try {
+                    wait(REGISTRATION_CALLBACK_TIMEOUT_SECONDS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Callback reg wait interrupted: " + e);
+                }
+            }
+            return mLeHandle > 0;
+        }
+
+        public void stopLeScan() {
+            synchronized (this) {
+                if (mLeHandle <= 0) {
+                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+                    return;
+                }
+                try {
+                    mBluetoothGatt.stopScan(mLeHandle, false);
+                    mBluetoothGatt.unregisterClient(mLeHandle);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to stop scan and unregister" + e);
+                }
+                mLeHandle = -1;
+                notifyAll();
+            }
+        }
+
+        /**
+         * Application interface registered - app is ready to go
+         */
+        @Override
+        public void onClientRegistered(int status, int clientIf) {
+            Log.d(TAG, "onClientRegistered() - status=" + status +
+                    " clientIf=" + clientIf);
+
+            synchronized (this) {
+                if (mLeHandle == -1) {
+                    if (DBG)
+                        Log.d(TAG, "onClientRegistered LE scan canceled");
+                }
+
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    mLeHandle = clientIf;
+                    try {
+                        mBluetoothGatt.startScanWithFilters(mLeHandle, false, mSettings, mFilters);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "fail to start le scan: " + e);
+                        mLeHandle = -1;
+                    }
+                } else {
+                    // registration failed
+                    mLeHandle = -1;
+                }
+                notifyAll();
+            }
+        }
+
+        @Override
+        public void onClientConnectionState(int status, int clientIf,
+                boolean connected, String address) {
+            // no op
+        }
+
+        /**
+         * Callback reporting an LE scan result.
+         *
+         * @hide
+         */
+        @Override
+        public void onScanResult(String address, int rssi, byte[] advData) {
+            if (DBG)
+                Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" + rssi);
+
+            // Check null in case the scan has been stopped
+            synchronized (this) {
+                if (mLeHandle <= 0)
+                    return;
+            }
+            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
+                    address);
+            long scanMicros = TimeUnit.NANOSECONDS.toMicros(SystemClock.elapsedRealtimeNanos());
+            ScanResult result = new ScanResult(device, advData, rssi,
+                    scanMicros);
+            mScanCallback.onDeviceUpdate(result);
+        }
+
+        @Override
+        public void onGetService(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid) {
+            // no op
+        }
+
+        @Override
+        public void onGetIncludedService(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int inclSrvcType, int inclSrvcInstId,
+                ParcelUuid inclSrvcUuid) {
+            // no op
+        }
+
+        @Override
+        public void onGetCharacteristic(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int charProps) {
+            // no op
+        }
+
+        @Override
+        public void onGetDescriptor(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descUuid) {
+            // no op
+        }
+
+        @Override
+        public void onSearchComplete(String address, int status) {
+            // no op
+        }
+
+        @Override
+        public void onCharacteristicRead(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid, byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onCharacteristicWrite(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid) {
+            // no op
+        }
+
+        @Override
+        public void onNotify(String address, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onDescriptorRead(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descrUuid, byte[] value) {
+            // no op
+        }
+
+        @Override
+        public void onDescriptorWrite(String address, int status, int srvcType,
+                int srvcInstId, ParcelUuid srvcUuid,
+                int charInstId, ParcelUuid charUuid,
+                int descInstId, ParcelUuid descrUuid) {
+            // no op
+        }
+
+        @Override
+        public void onExecuteWrite(String address, int status) {
+            // no op
+        }
+
+        @Override
+        public void onReadRemoteRssi(String address, int rssi, int status) {
+            // no op
+        }
+
+        @Override
+        public void onAdvertiseStateChange(int advertiseState, int status) {
+            // no op
+        }
+
+        @Override
+        public void onMultiAdvertiseCallback(int status) {
+            // no op
+        }
+
+        @Override
+        public void onConfigureMTU(String address, int mtu, int status) {
+            // no op
+        }
+    }
+
+    /**
+     * Scan Bluetooth LE scan. The scan results will be delivered through {@code callback}.
+     *
+     * @param filters {@link BluetoothLeScanFilter}s for finding exact BLE devices.
+     * @param settings Settings for ble scan.
+     * @param callback Callback when scan results are delivered.
+     * @throws IllegalArgumentException If {@code settings} or {@code callback} is null.
+     */
+    public void startScan(List<BluetoothLeScanFilter> filters, Settings settings,
+            final ScanCallback callback) {
+        if (settings == null || callback == null) {
+            throw new IllegalArgumentException("settings or callback is null");
+        }
+        synchronized (mLeScanClients) {
+            if (mLeScanClients.get(settings) != null) {
+                postCallbackError(callback, ScanCallback.SCAN_ALREADY_STARTED);
+                return;
+            }
+            BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(mBluetoothGatt, filters,
+                    settings, callback);
+            try {
+                UUID uuid = UUID.randomUUID();
+                mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+                if (wrapper.scanStarted()) {
+                    mLeScanClients.put(settings, wrapper);
+                } else {
+                    postCallbackError(callback, ScanCallback.APPLICATION_REGISTRATION_FAILED);
+                    return;
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "GATT service exception when starting scan", e);
+                postCallbackError(callback, ScanCallback.GATT_SERVICE_FAILURE);
+            }
+        }
+    }
+
+    private void postCallbackError(final ScanCallback callback, final int errorCode) {
+        mHandler.post(new Runnable() {
+                @Override
+            public void run() {
+                callback.onScanFailed(errorCode);
+            }
+        });
+    }
+
+    /**
+     * Stop Bluetooth LE scan.
+     *
+     * @param settings The same settings as used in {@link #startScan}, which is used to identify
+     *            the BLE scan.
+     */
+    public void stopScan(Settings settings) {
+        synchronized (mLeScanClients) {
+            BleScanCallbackWrapper wrapper = mLeScanClients.remove(settings);
+            if (wrapper == null) {
+                return;
+            }
+            wrapper.stopLeScan();
+        }
+    }
+
+    /**
+     * Returns available storage size for batch scan results. It's recommended not to use batch scan
+     * if available storage size is small (less than 1k bytes, for instance).
+     *
+     * @hide TODO: unhide when batching is supported in stack.
+     */
+    public int getAvailableBatchStorageSizeBytes() {
+        throw new UnsupportedOperationException("not impelemented");
+    }
+
+    /**
+     * Poll scan results from bluetooth controller. This will return Bluetooth LE scan results
+     * batched on bluetooth controller.
+     *
+     * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
+     *            used to start scan.
+     * @param flush Whether to flush the batch scan buffer. Note the other batch scan clients will
+     *            get batch scan callback if the batch scan buffer is flushed.
+     * @return Batch Scan results.
+     * @hide TODO: unhide when batching is supported in stack.
+     */
+    public List<ScanResult> getBatchScanResults(ScanCallback callback, boolean flush) {
+        throw new UnsupportedOperationException("not impelemented");
+    }
+
+}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index ab53fb0..1e22eb3 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -273,11 +273,29 @@
      * @param parcelUuid
      * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
      */
-    public static boolean isShortUuid(ParcelUuid parcelUuid) {
+    public static boolean is16BitUuid(ParcelUuid parcelUuid) {
         UUID uuid = parcelUuid.getUuid();
         if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
             return false;
         }
         return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
     }
+
+
+    /**
+     * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
+     *
+     * @param parcelUuid
+     * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
+     */
+    public static boolean is32BitUuid(ParcelUuid parcelUuid) {
+        UUID uuid = parcelUuid.getUuid();
+        if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+            return false;
+        }
+        if (is16BitUuid(parcelUuid)) {
+            return false;
+        }
+        return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
+    }
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 3dd7094..091b806 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -17,6 +17,10 @@
 package android.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAdvertiseScanData;
+import android.bluetooth.BluetoothLeAdvertiser;
+import android.bluetooth.BluetoothLeScanFilter;
+import android.bluetooth.BluetoothLeScanner;
 import android.os.ParcelUuid;
 
 import android.bluetooth.IBluetoothGattCallback;
@@ -33,8 +37,13 @@
     void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
     void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
                     in ParcelUuid[] ids, int scanWindow, int scanInterval);
+    void startScanWithFilters(in int appIf, in boolean isServer,
+                              in BluetoothLeScanner.Settings settings,
+                              in List<BluetoothLeScanFilter> filters);
     void stopScan(in int appIf, in boolean isServer);
-
+    void startMultiAdvertising(in int appIf, in BluetoothLeAdvertiseScanData.AdvertisementData data,
+                               in BluetoothLeAdvertiser.Settings settings);
+    void stopMultiAdvertising(in int appIf);
     void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
     void unregisterClient(in int clientIf);
     void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index a78c29b..bf9e0a7 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -64,5 +64,6 @@
                              in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     oneway void onAdvertiseStateChange(in int advertiseState, in int status);
+    oneway void onMultiAdvertiseCallback(in int status);
     void onConfigureMTU(in String address, in int mtu, in int status);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0e2eab7..35bcc02 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1405,6 +1405,14 @@
     public static final String FEATURE_MANAGEDPROFILES = "android.software.managedprofiles";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device has a full implementation of the android.webkit.* APIs. Devices
+     * lacking this feature will not have a functioning WebView implementation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_WEBVIEW = "android.software.webview";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 5674154..3f01dd2 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -64,7 +64,6 @@
  * List Resource</a>.</p>
  */
 public class ColorStateList implements Parcelable {
-
     private int[][] mStateSpecs; // must be parallel to mColors
     private int[] mColors;      // must be parallel to mStateSpecs
     private int mDefaultColor = 0xffff0000;
@@ -100,9 +99,9 @@
     public static ColorStateList valueOf(int color) {
         // TODO: should we collect these eventually?
         synchronized (sCache) {
-            WeakReference<ColorStateList> ref = sCache.get(color);
-            ColorStateList csl = ref != null ? ref.get() : null;
+            final WeakReference<ColorStateList> ref = sCache.get(color);
 
+            ColorStateList csl = ref != null ? ref.get() : null;
             if (csl != null) {
                 return csl;
             }
@@ -118,8 +117,7 @@
      */
     public static ColorStateList createFromXml(Resources r, XmlPullParser parser)
             throws XmlPullParserException, IOException {
-
-        AttributeSet attrs = Xml.asAttributeSet(parser);
+        final AttributeSet attrs = Xml.asAttributeSet(parser);
 
         int type;
         while ((type=parser.next()) != XmlPullParser.START_TAG
@@ -133,22 +131,22 @@
         return createFromXmlInner(r, parser, attrs);
     }
 
-    /* Create from inside an XML document.  Called on a parser positioned at
-     * a tag in an XML document, tries to create a ColorStateList from that tag.
-     * Returns null if the tag is not a valid ColorStateList.
+    /**
+     * Create from inside an XML document. Called on a parser positioned at a
+     * tag in an XML document, tries to create a ColorStateList from that tag.
+     *
+     * @throws XmlPullParserException if the current tag is not &lt;selector>
+     * @return A color state list for the current tag.
      */
     private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser,
             AttributeSet attrs) throws XmlPullParserException, IOException {
-
-        ColorStateList colorStateList;
-
+        final ColorStateList colorStateList;
         final String name = parser.getName();
-
         if (name.equals("selector")) {
             colorStateList = new ColorStateList();
         } else {
             throw new XmlPullParserException(
-                parser.getPositionDescription() + ": invalid drawable tag " + name);
+                    parser.getPositionDescription() + ": invalid drawable tag " + name);
         }
 
         colorStateList.inflate(r, parser, attrs);
@@ -161,9 +159,8 @@
      * (0-255).
      */
     public ColorStateList withAlpha(int alpha) {
-        int[] colors = new int[mColors.length];
-
-        int len = colors.length;
+        final int[] colors = new int[mColors.length];
+        final int len = colors.length;
         for (int i = 0; i < len; i++) {
             colors[i] = (mColors[i] & 0xFFFFFF) | (alpha << 24);
         }
@@ -176,7 +173,6 @@
      */
     private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
             throws XmlPullParserException, IOException {
-
         int type;
 
         final int innerDepth = parser.getDepth()+1;
@@ -259,10 +255,25 @@
         System.arraycopy(stateSpecList, 0, mStateSpecs, 0, listSize);
     }
 
+    /**
+     * Indicates whether this color state list contains more than one state spec
+     * and will change color based on state.
+     *
+     * @return True if this color state list changes color based on state, false
+     *         otherwise.
+     * @see #getColorForState(int[], int)
+     */
     public boolean isStateful() {
         return mStateSpecs.length > 1;
     }
 
+    /**
+     * Indicates whether this color state list is opaque, which means that every
+     * color returned from {@link #getColorForState(int[], int)} has an alpha
+     * value of 255.
+     *
+     * @return True if this color state list is opaque.
+     */
     public boolean isOpaque() {
         final int n = mColors.length;
         for (int i = 0; i < n; i++) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1692a79..a78f8e2 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -21,6 +21,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
@@ -719,12 +720,12 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @param theme The theme used to style the drawable attributes.
+     * @param theme The theme used to style the drawable attributes, may be {@code null}.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist.
      */
-    public Drawable getDrawable(int id, Theme theme) throws NotFoundException {
+    public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -777,12 +778,12 @@
      *            The value 0 is an invalid identifier.
      * @param density The desired screen density indicated by the resource as
      *            found in {@link DisplayMetrics}.
-     * @param theme The theme used to style the drawable attributes.
+     * @param theme The theme used to style the drawable attributes, may be {@code null}.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *             not exist.
      */
-    public Drawable getDrawableForDensity(int id, int density, Theme theme) {
+    public Drawable getDrawableForDensity(int id, int density, @Nullable Theme theme) {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
index 92d6f75..da5c128 100644
--- a/core/java/android/hardware/usb/UsbConfiguration.java
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -44,13 +44,13 @@
      * Mask for "self-powered" bit in the configuration's attributes.
      * @see #getAttributes
      */
-    public static final int ATTR_SELF_POWERED_MASK = 1 << 6;
+    private static final int ATTR_SELF_POWERED = 1 << 6;
 
     /**
      * Mask for "remote wakeup" bit in the configuration's attributes.
      * @see #getAttributes
      */
-    public static final int ATTR_REMOTE_WAKEUP_MASK = 1 << 5;
+    private static final int ATTR_REMOTE_WAKEUP = 1 << 5;
 
     /**
      * UsbConfiguration should only be instantiated by UsbService implementation
@@ -83,19 +83,23 @@
     }
 
     /**
-     * Returns the configuration's attributes field.
-     * This field contains a bit field with the following flags:
+     * Returns the self-powered attribute value configuration's attributes field.
+     * This attribute indicates that the device has a power source other than the USB connection.
      *
-     * Bit 7: always set to 1
-     * Bit 6: self-powered
-     * Bit 5: remote wakeup enabled
-     * Bit 0-4: reserved
-     * @see #ATTR_SELF_POWERED_MASK
-     * @see #ATTR_REMOTE_WAKEUP_MASK
-     * @return the configuration's attributes
+     * @return the configuration's self-powered attribute
      */
-    public int getAttributes() {
-        return mAttributes;
+    public boolean isSelfPowered() {
+        return (mAttributes & ATTR_SELF_POWERED) != 0;
+    }
+
+    /**
+     * Returns the remote-wakeup attribute value configuration's attributes field.
+     * This attributes that the device may signal the host to wake from suspend.
+     *
+     * @return the configuration's remote-wakeup attribute
+     */
+    public boolean isRemoteWakeup() {
+        return (mAttributes & ATTR_REMOTE_WAKEUP) != 0;
     }
 
     /**
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 6283951..c062b3a 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -104,7 +104,7 @@
      * Sets the current {@link android.hardware.usb.UsbInterface}.
      * Used to select between two interfaces with the same ID but different alternate setting.
      *
-     * @return true if the interface was successfully released
+     * @return true if the interface was successfully selected
      */
     public boolean setInterface(UsbInterface intf) {
         return native_set_interface(intf.getId(), intf.getAlternateSetting());
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1837335..80a9598 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1655,9 +1655,16 @@
     }
 
     /** {@hide} */
-    public void registerNetworkFactory(Messenger messenger) {
+    public void registerNetworkFactory(Messenger messenger, String name) {
         try {
-            mService.registerNetworkFactory(messenger);
+            mService.registerNetworkFactory(messenger, name);
+        } catch (RemoteException e) { }
+    }
+
+    /** {@hide} */
+    public void unregisterNetworkFactory(Messenger messenger) {
+        try {
+            mService.unregisterNetworkFactory(messenger);
         } catch (RemoteException e) { }
     }
 
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 885b8b6..d97b1e9 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -153,7 +153,9 @@
 
     void setAirplaneMode(boolean enable);
 
-    void registerNetworkFactory(in Messenger messenger);
+    void registerNetworkFactory(in Messenger messenger, in String name);
+
+    void unregisterNetworkFactory(in Messenger messenger);
 
     void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
             in NetworkCapabilities nc, int score);
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
new file mode 100644
index 0000000..4730bab
--- /dev/null
+++ b/core/java/android/net/IpConfiguration.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.LinkProperties;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A class representing a configured network.
+ * @hide
+ */
+public class IpConfiguration implements Parcelable {
+    private static final String TAG = "IpConfiguration";
+
+    public enum IpAssignment {
+        /* Use statically configured IP settings. Configuration can be accessed
+         * with linkProperties */
+        STATIC,
+        /* Use dynamically configured IP settigns */
+        DHCP,
+        /* no IP details are assigned, this is used to indicate
+         * that any existing IP settings should be retained */
+        UNASSIGNED
+    }
+
+    public IpAssignment ipAssignment;
+
+    public enum ProxySettings {
+        /* No proxy is to be used. Any existing proxy settings
+         * should be cleared. */
+        NONE,
+        /* Use statically configured proxy. Configuration can be accessed
+         * with linkProperties */
+        STATIC,
+        /* no proxy details are assigned, this is used to indicate
+         * that any existing proxy settings should be retained */
+        UNASSIGNED,
+        /* Use a Pac based proxy.
+         */
+        PAC
+    }
+
+    public ProxySettings proxySettings;
+
+    public LinkProperties linkProperties;
+
+    public IpConfiguration(IpConfiguration source) {
+        if (source != null) {
+            ipAssignment = source.ipAssignment;
+            proxySettings = source.proxySettings;
+            linkProperties = new LinkProperties(source.linkProperties);
+        } else {
+            ipAssignment = IpAssignment.UNASSIGNED;
+            proxySettings = ProxySettings.UNASSIGNED;
+            linkProperties = new LinkProperties();
+        }
+    }
+
+    public IpConfiguration() {
+         this(null);
+    }
+
+    public IpConfiguration(IpAssignment ipAssignment,
+                           ProxySettings proxySettings,
+                           LinkProperties linkProperties) {
+        this.ipAssignment = ipAssignment;
+        this.proxySettings = proxySettings;
+        this.linkProperties = new LinkProperties(linkProperties);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("IP assignment: " + ipAssignment.toString());
+        sbuf.append("\n");
+        sbuf.append("Proxy settings: " + proxySettings.toString());
+        sbuf.append("\n");
+        sbuf.append(linkProperties.toString());
+        sbuf.append("\n");
+
+        return sbuf.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof IpConfiguration)) {
+            return false;
+        }
+
+        IpConfiguration other = (IpConfiguration) o;
+        return this.ipAssignment == other.ipAssignment &&
+                this.proxySettings == other.proxySettings &&
+                Objects.equals(this.linkProperties, other.linkProperties);
+    }
+
+    @Override
+    public int hashCode() {
+        return 13 + (linkProperties != null ? linkProperties.hashCode() : 0) +
+               17 * ipAssignment.ordinal() +
+               47 * proxySettings.ordinal();
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface  */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(ipAssignment.name());
+        dest.writeString(proxySettings.name());
+        dest.writeParcelable(linkProperties, flags);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<IpConfiguration> CREATOR =
+        new Creator<IpConfiguration>() {
+            public IpConfiguration createFromParcel(Parcel in) {
+                IpConfiguration config = new IpConfiguration();
+                config.ipAssignment = IpAssignment.valueOf(in.readString());
+                config.proxySettings = ProxySettings.valueOf(in.readString());
+                config.linkProperties = in.readParcelable(null);
+                return config;
+            }
+
+            public IpConfiguration[] newArray(int size) {
+                return new IpConfiguration[size];
+            }
+        };
+}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ceedd98..7ea6bae 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -155,9 +155,6 @@
             mHost = source.getHost();
             mPort = source.getPort();
             mPacFileUrl = source.mPacFileUrl;
-            if (mPacFileUrl == null) {
-                mPacFileUrl = Uri.EMPTY;
-            }
             mExclusionList = source.getExclusionListAsString();
             mParsedExclusionList = source.mParsedExclusionList;
         } else {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 312cdbe..ee219e3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -266,6 +266,17 @@
      */
     public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
 
+    /**
+     * Key for user restrictions. Specifies that the user is not allowed to send or receive
+     * phone calls or text messages. Emergency calls may still be permitted.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_TELEPHONY = "no_telephony";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e896063..2d03e1d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1088,6 +1088,9 @@
             MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_COUNT);
             MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_DELAY_MS);
             MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS);
+
+            // At one time in System, then Global, but now back in Secure
+            MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
         }
 
         private static final HashSet<String> MOVED_TO_GLOBAL;
@@ -1102,7 +1105,6 @@
             MOVED_TO_SECURE_THEN_GLOBAL.add(Global.BLUETOOTH_ON);
             MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DATA_ROAMING);
             MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DEVICE_PROVISIONED);
-            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS);
             MOVED_TO_SECURE_THEN_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_SECURE_THEN_GLOBAL.add(Global.HTTP_PROXY);
 
@@ -2573,10 +2575,10 @@
         public static final String HTTP_PROXY = Global.HTTP_PROXY;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead
+         * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead
          */
         @Deprecated
-        public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS;
+        public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED}
@@ -2814,7 +2816,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED);
             MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
             MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
-            MOVED_TO_GLOBAL.add(Settings.Global.INSTALL_NON_MARKET_APPS);
             MOVED_TO_GLOBAL.add(Settings.Global.MOBILE_DATA);
             MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION);
             MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_DELETE_AGE);
@@ -3404,10 +3405,13 @@
         public static final String HTTP_PROXY = Global.HTTP_PROXY;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead
+         * Whether applications can be installed for this user via the system's
+         * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
+         *
+         * <p>1 = permit app installation via the system package installer intent
+         * <p>0 = do not allow use of the package installer
          */
-        @Deprecated
-        public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS;
+        public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
 
         /**
          * Comma-separated list of location providers that activities may access. Do not rely on
@@ -5066,13 +5070,10 @@
                "download_manager_recommended_max_bytes_over_mobile";
 
        /**
-        * Whether the package installer should allow installation of apps downloaded from
-        * sources other than Google Play.
-        *
-        * 1 = allow installing from other sources
-        * 0 = only allow installing from Google Play
+        * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead
         */
-       public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+       @Deprecated
+       public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
 
        /**
         * Whether mobile data connections are allowed by the user.  See
@@ -6238,6 +6239,13 @@
                     CALL_METHOD_GET_GLOBAL,
                     CALL_METHOD_PUT_GLOBAL);
 
+        // Certain settings have been moved from global to the per-user secure namespace
+        private static final HashSet<String> MOVED_TO_SECURE;
+        static {
+            MOVED_TO_SECURE = new HashSet<String>(1);
+            MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
@@ -6251,6 +6259,11 @@
         /** @hide */
         public static String getStringForUser(ContentResolver resolver, String name,
                 int userHandle) {
+            if (MOVED_TO_SECURE.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
+                        + " to android.provider.Settings.Secure, returning read-only value.");
+                return Secure.getStringForUser(resolver, name, userHandle);
+            }
             return sNameValueCache.getStringForUser(resolver, name, userHandle);
         }
 
@@ -6273,6 +6286,12 @@
                 Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
                         + " for " + userHandle);
             }
+            // Global and Secure have the same access policy so we can forward writes
+            if (MOVED_TO_SECURE.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
+                        + " to android.provider.Settings.Secure, value is unchanged.");
+                return Secure.putStringForUser(resolver, name, value, userHandle);
+            }
             return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
         }
 
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 0d14c59..2fcec52 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
@@ -25,6 +26,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 
 /**
@@ -33,7 +35,7 @@
 
 public class FingerprintManager {
     private static final String TAG = "FingerprintManager";
-    protected static final boolean DEBUG = true;
+    private static final boolean DEBUG = true;
     private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
     private static final String FINGERPRINT_SERVICE_CLASS =
             "com.android.service.fingerprint.FingerprintService";
@@ -58,6 +60,7 @@
 
     private IFingerprintService mService;
     private FingerprintManagerReceiver mClientReceiver;
+    private Context mContext;
 
     private Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
@@ -80,6 +83,7 @@
     };
 
     public FingerprintManager(Context context) {
+        mContext = context;
         // Connect to service...
         Intent intent = new Intent();
         intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
@@ -129,6 +133,17 @@
     };
 
     /**
+     * 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.
      *
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index d4919eb..b3705d8 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -17,15 +17,15 @@
 package android.service.notification;
 
 import android.service.notification.StatusBarNotification;
-import android.service.notification.NotificationOrderUpdate;
+import android.service.notification.NotificationRankingUpdate;
 
 /** @hide */
 oneway interface INotificationListener
 {
-    void onListenerConnected(in NotificationOrderUpdate update);
+    void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in StatusBarNotification notification,
-            in NotificationOrderUpdate update);
+            in NotificationRankingUpdate update);
     void onNotificationRemoved(in StatusBarNotification notification,
-            in NotificationOrderUpdate update);
-    void onNotificationOrderUpdate(in NotificationOrderUpdate update);
+            in NotificationRankingUpdate update);
+    void onNotificationRankingUpdate(in NotificationRankingUpdate update);
 }
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index e2e9ff4..7f84877 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -24,12 +24,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
 /**
- * A service that receives calls from the system when new notifications are posted or removed.
+ * A service that receives calls from the system when new notifications are
+ * posted or removed, or their ranking changed.
  * <p>To extend this class, you must declare the service in your manifest file with
  * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
@@ -48,7 +51,7 @@
             + "[" + getClass().getSimpleName() + "]";
 
     private INotificationListenerWrapper mWrapper = null;
-    private String[] mNotificationKeys;
+    private Ranking mRanking;
 
     private INotificationManager mNoMan;
 
@@ -102,11 +105,11 @@
     }
 
     /**
-     * Implement this method to be notified when the notification order cahnges.
-     *
-     * Call {@link #getOrderedNotificationKeys()} to retrieve the new order.
+     * Implement this method to be notified when the notification ranking changes.
+     * <P>
+     * Call {@link #getCurrentRanking()} to retrieve the new ranking.
      */
-    public void onNotificationOrderUpdate() {
+    public void onNotificationRankingUpdate() {
         // optional
     }
 
@@ -224,6 +227,19 @@
     }
 
     /**
+     * Request the list of notification keys in their current ranking order.
+     * <p>
+     * You can use the notification keys for subsequent retrieval via
+     * {@link #getActiveNotifications(String[]) or dismissal via
+     * {@link #cancelNotifications(String[]).
+     *
+     * @return An array of active notification keys, in their ranking order.
+     */
+    public String[] getActiveNotificationKeys() {
+        return mRanking.getOrderedKeys();
+    }
+
+    /**
      * Request the list of outstanding notifications (that is, those that are visible to the
      * current user). Useful when you don't know what's already been posted.
      *
@@ -242,15 +258,20 @@
     }
 
     /**
-     * Request the list of notification keys in their current natural order.
-     * You can use the notification keys for subsequent retrieval via
-     * {@link #getActiveNotifications(String[]) or dismissal via
-     * {@link #cancelNotifications(String[]).
+     * Returns current ranking information.
      *
-     * @return An array of active notification keys, in their natural order.
+     * <p>
+     * The returned object represents the current ranking snapshot and only
+     * applies for currently active notifications. Hence you must retrieve a
+     * new Ranking after each notification event such as
+     * {@link #onNotificationPosted(StatusBarNotification)},
+     * {@link #onNotificationRemoved(StatusBarNotification)}, etc.
+     *
+     * @return A {@link NotificationListenerService.Ranking} object providing
+     *     access to ranking information
      */
-    public String[] getOrderedNotificationKeys() {
-        return mNotificationKeys;
+    public Ranking getCurrentRanking() {
+        return mRanking;
     }
 
     @Override
@@ -308,59 +329,163 @@
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn,
-                NotificationOrderUpdate update) {
-            try {
-                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-                synchronized (mWrapper) {
-                    updateNotificationKeys(update);
+                NotificationRankingUpdate update) {
+            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+            synchronized (mWrapper) {
+                applyUpdate(update);
+                try {
                     NotificationListenerService.this.onNotificationPosted(sbn);
+                } catch (Throwable t) {
+                    Log.w(TAG, "Error running onNotificationPosted", t);
                 }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onOrderedNotificationPosted", t);
             }
         }
         @Override
         public void onNotificationRemoved(StatusBarNotification sbn,
-                NotificationOrderUpdate update) {
-            try {
-                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-                synchronized (mWrapper) {
-                    updateNotificationKeys(update);
+                NotificationRankingUpdate update) {
+            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+            synchronized (mWrapper) {
+                applyUpdate(update);
+                try {
                     NotificationListenerService.this.onNotificationRemoved(sbn);
+                } catch (Throwable t) {
+                    Log.w(TAG, "Error running onNotificationRemoved", t);
                 }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationRemoved", t);
             }
         }
         @Override
-        public void onListenerConnected(NotificationOrderUpdate update) {
-            try {
-                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-                synchronized (mWrapper) {
-                    updateNotificationKeys(update);
-                    NotificationListenerService.this.onListenerConnected(mNotificationKeys);
+        public void onListenerConnected(NotificationRankingUpdate update) {
+            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+            synchronized (mWrapper) {
+                applyUpdate(update);
+                try {
+                    NotificationListenerService.this.onListenerConnected(
+                            mRanking.getOrderedKeys());
+                } catch (Throwable t) {
+                    Log.w(TAG, "Error running onListenerConnected", t);
                 }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onListenerConnected", t);
             }
         }
         @Override
-        public void onNotificationOrderUpdate(NotificationOrderUpdate update)
+        public void onNotificationRankingUpdate(NotificationRankingUpdate update)
                 throws RemoteException {
-            try {
-                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-                synchronized (mWrapper) {
-                    updateNotificationKeys(update);
-                    NotificationListenerService.this.onNotificationOrderUpdate();
+            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+            synchronized (mWrapper) {
+                applyUpdate(update);
+                try {
+                    NotificationListenerService.this.onNotificationRankingUpdate();
+                } catch (Throwable t) {
+                    Log.w(TAG, "Error running onNotificationRankingUpdate", t);
                 }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationOrderUpdate", t);
             }
         }
     }
 
-    private void updateNotificationKeys(NotificationOrderUpdate update) {
-        // TODO: avoid garbage by comparing the lists
-        mNotificationKeys = update.getOrderedKeys();
+    private void applyUpdate(NotificationRankingUpdate update) {
+        mRanking = new Ranking(update);
+    }
+
+    /**
+     * Provides access to ranking information on currently active
+     * notifications.
+     *
+     * <p>
+     * Note that this object represents a ranking snapshot that only applies to
+     * notifications active at the time of retrieval.
+     */
+    public static class Ranking implements Parcelable {
+        private final NotificationRankingUpdate mRankingUpdate;
+
+        private Ranking(NotificationRankingUpdate rankingUpdate) {
+            mRankingUpdate = rankingUpdate;
+        }
+
+        /**
+         * Request the list of notification keys in their current ranking
+         * order.
+         *
+         * @return An array of active notification keys, in their ranking order.
+         */
+        public String[] getOrderedKeys() {
+            return mRankingUpdate.getOrderedKeys();
+        }
+
+        /**
+         * Returns the rank of the notification with the given key, that is the
+         * index of <code>key</code> in the array of keys returned by
+         * {@link #getOrderedKeys()}.
+         *
+         * @return The rank of the notification with the given key; -1 when the
+         *      given key is unknown.
+         */
+        public int getIndexOfKey(String key) {
+            // TODO: Optimize.
+            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
+            for (int i = 0; i < orderedKeys.length; i++) {
+                if (orderedKeys[i].equals(key)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Returns whether the notification with the given key was intercepted
+         * by &quot;Do not disturb&quot;.
+         */
+        public boolean isInterceptedByDoNotDisturb(String key) {
+            // TODO: Optimize.
+            for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
+                if (interceptedKey.equals(key)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns whether the notification with the given key is an ambient
+         * notification, that is a notification that doesn't require the user's
+         * immediate attention.
+         */
+        public boolean isAmbient(String key) {
+            // TODO: Optimize.
+            int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
+            if (firstAmbientIndex < 0) {
+                return false;
+            }
+            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
+            for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
+                if (orderedKeys[i].equals(key)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        // ----------- Parcelable
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(mRankingUpdate, flags);
+        }
+
+        public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
+            @Override
+            public Ranking createFromParcel(Parcel source) {
+                NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
+                return new Ranking(rankingUpdate);
+            }
+
+            @Override
+            public Ranking[] newArray(int size) {
+                return new Ranking[size];
+            }
+        };
     }
 }
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.java b/core/java/android/service/notification/NotificationOrderUpdate.java
deleted file mode 100644
index 20e19a3..0000000
--- a/core/java/android/service/notification/NotificationOrderUpdate.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.service.notification;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class NotificationOrderUpdate implements Parcelable {
-    // TODO replace this with an update instead of the whole array
-    private final String[] mKeys;
-
-    /** @hide */
-    public NotificationOrderUpdate(String[] keys) {
-        this.mKeys = keys;
-    }
-
-    public NotificationOrderUpdate(Parcel in) {
-        this.mKeys = in.readStringArray();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeStringArray(this.mKeys);
-    }
-
-    public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR
-            = new Parcelable.Creator<NotificationOrderUpdate>() {
-        public NotificationOrderUpdate createFromParcel(Parcel parcel) {
-            return new NotificationOrderUpdate(parcel);
-        }
-
-        public NotificationOrderUpdate[] newArray(int size) {
-            return new NotificationOrderUpdate[size];
-        }
-    };
-
-    /**
-     * @hide
-     * @return ordered list of keys
-     */
-    String[] getOrderedKeys() {
-        return mKeys;
-    }
-}
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/service/notification/NotificationRankingUpdate.aidl
similarity index 94%
rename from core/java/android/service/notification/NotificationOrderUpdate.aidl
rename to core/java/android/service/notification/NotificationRankingUpdate.aidl
index 5d50641..1393cb9 100644
--- a/core/java/android/service/notification/NotificationOrderUpdate.aidl
+++ b/core/java/android/service/notification/NotificationRankingUpdate.aidl
@@ -16,4 +16,4 @@
 
 package android.service.notification;
 
-parcelable NotificationOrderUpdate;
+parcelable NotificationRankingUpdate;
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
new file mode 100644
index 0000000..4b13d95
--- /dev/null
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.notification;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class NotificationRankingUpdate implements Parcelable {
+    // TODO: Support incremental updates.
+    private final String[] mKeys;
+    private final String[] mDndInterceptedKeys;
+    private final int mFirstAmbientIndex;
+
+    public NotificationRankingUpdate(String[] keys, String[] dndInterceptedKeys,
+                                     int firstAmbientIndex) {
+        mKeys = keys;
+        mFirstAmbientIndex = firstAmbientIndex;
+        mDndInterceptedKeys = dndInterceptedKeys;
+    }
+
+    public NotificationRankingUpdate(Parcel in) {
+        mKeys = in.readStringArray();
+        mFirstAmbientIndex = in.readInt();
+        mDndInterceptedKeys = in.readStringArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStringArray(mKeys);
+        out.writeInt(mFirstAmbientIndex);
+        out.writeStringArray(mDndInterceptedKeys);
+    }
+
+    public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
+            = new Parcelable.Creator<NotificationRankingUpdate>() {
+        public NotificationRankingUpdate createFromParcel(Parcel parcel) {
+            return new NotificationRankingUpdate(parcel);
+        }
+
+        public NotificationRankingUpdate[] newArray(int size) {
+            return new NotificationRankingUpdate[size];
+        }
+    };
+
+    public String[] getOrderedKeys() {
+        return mKeys;
+    }
+
+    public int getFirstAmbientIndex() {
+        return mFirstAmbientIndex;
+    }
+
+    public String[] getDndInterceptedKeys() {
+        return mDndInterceptedKeys;
+    }
+}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 0bd46bc..b17f502 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -115,7 +115,7 @@
             if (count > 0 && selStart == selEnd && selStart > 0) {
                 char c = content.charAt(selStart - 1);
 
-                if (c == i || c == Character.toUpperCase(i) && view != null) {
+                if ((c == i || c == Character.toUpperCase(i)) && view != null) {
                     if (showCharacterPicker(view, content, c, false, count)) {
                         resetMetaState(content);
                         return true;
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 7721575..59b6386 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -149,6 +149,7 @@
         if (mSession != null) {
             release();
         }
+        mSessionCallback = null;
     }
 
     /**
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index ae5f37e..358ae8a 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -234,6 +234,14 @@
     public static final int SOURCE_JOYSTICK = 0x01000000 | SOURCE_CLASS_JOYSTICK;
 
     /**
+     * The input source is a device connected through HDMI-based bus.
+     *
+     * The key comes in through HDMI-CEC or MHL signal line, and is treated as if it were
+     * generated by a locally connected DPAD or keyboard.
+     */
+    public static final int SOURCE_HDMI = 0x02000000 | SOURCE_CLASS_BUTTON;
+
+    /**
      * A special input source constant that is used when filtering input devices
      * to match devices that provide any type of input source.
      */
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index b8e1b89..8a996d2 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -644,14 +644,26 @@
      * devices or game controllers, especially if no other input mode is
      * available. */
     public static final int KEYCODE_PAIRING         = 225;
+    /** Key code constant: Media Top Menu key.
+     * Goes to the top of media menu. */
+    public static final int KEYCODE_MEDIA_TOP_MENU  = 226;
+    /** Key code constant: '11' key. */
+    public static final int KEYCODE_11              = 227;
+    /** Key code constant: '12' key. */
+    public static final int KEYCODE_12              = 228;
+    /** Key code constant: Last Channel key.
+     * Goes to the last viewed channel. */
+    public static final int KEYCODE_LAST_CHANNEL    = 229;
+    /** Key code constant: TV data service key.
+     * Displays data services like weather, sports. */
+    public static final int KEYCODE_TV_DATA_SERVICE = 230;
 
-    private static final int LAST_KEYCODE = KEYCODE_PAIRING;
+    private static final int LAST_KEYCODE = KEYCODE_TV_DATA_SERVICE;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
     //  frameworks/native/include/android/keycodes.h
-    //  frameworks/base/include/androidfw/InputEventAttributes.h
-    //  external/webkit/WebKit/android/plugins/ANPKeyCodes.h
+    //  frameworks/native/include/input/InputEventLabels.h
     //  frameworks/base/core/res/res/values/attrs.xml
     //  emulator?
     //  LAST_KEYCODE
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c1a4fee..e918119 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -48,6 +48,8 @@
     public static final int Y = 9;
     public static final int Z = 10;
     public static final int ALPHA = 11;
+    // The last value in the enum, used for array size initialization
+    public static final int LAST_VALUE = ALPHA;
 
     // Keep in sync with enum PaintFields in Animator.h
     public static final int PAINT_STROKE_WIDTH = 0;
@@ -86,7 +88,7 @@
     private boolean mStarted = false;
     private boolean mFinished = false;
 
-    public int mapViewPropertyToRenderProperty(int viewProperty) {
+    public static int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
     }
 
@@ -125,11 +127,15 @@
         }
     }
 
+    static boolean isNativeInterpolator(TimeInterpolator interpolator) {
+        return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
+    }
+
     private void applyInterpolator() {
         if (mInterpolator == null) return;
 
         long ni;
-        if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
+        if (isNativeInterpolator(mInterpolator)) {
             ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
         } else {
             long duration = nGetDuration(mNativePtr.get());
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 11d2622..3104862 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.animation.TimeInterpolator;
+import android.os.Build;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -109,6 +110,11 @@
     private ValueAnimator mTempValueAnimator;
 
     /**
+     * A RenderThread-driven backend that may intercept startAnimation
+     */
+    private ViewPropertyAnimatorRT mRTBackend;
+
+    /**
      * This listener is the mechanism by which the underlying Animator causes changes to the
      * properties currently being animated, as well as the cleanup after an animation is
      * complete.
@@ -227,7 +233,7 @@
      * values are used to calculate the animated value for a given animation fraction
      * during the animation.
      */
-    private static class NameValuesHolder {
+    static class NameValuesHolder {
         int mNameConstant;
         float mFromValue;
         float mDeltaValue;
@@ -247,6 +253,9 @@
     ViewPropertyAnimator(View view) {
         mView = view;
         view.ensureTransformationInfo();
+        if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
+            mRTBackend = new ViewPropertyAnimatorRT(view);
+        }
     }
 
     /**
@@ -371,6 +380,10 @@
         return this;
     }
 
+    Animator.AnimatorListener getListener() {
+        return mListener;
+    }
+
     /**
      * Sets a listener for update events in the underlying ValueAnimator that runs
      * the property animations. Note that the underlying animator is animating between
@@ -390,6 +403,10 @@
         return this;
     }
 
+    ValueAnimator.AnimatorUpdateListener getUpdateListener() {
+        return mUpdateListener;
+    }
+
     /**
      * Starts the currently pending property animations immediately. Calling <code>start()</code>
      * is optional because all animations start automatically at the next opportunity. However,
@@ -825,12 +842,22 @@
         return this;
     }
 
+    boolean hasActions() {
+        return mPendingSetupAction != null
+                || mPendingCleanupAction != null
+                || mPendingOnStartAction != null
+                || mPendingOnEndAction != null;
+    }
+
     /**
      * Starts the underlying Animator for a set of properties. We use a single animator that
      * simply runs from 0 to 1, and then use that fractional value to set each property
      * value accordingly.
      */
     private void startAnimation() {
+        if (mRTBackend != null && mRTBackend.startAnimation(this)) {
+            return;
+        }
         mView.setHasTransientState(true);
         ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
         ArrayList<NameValuesHolder> nameValueList =
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
new file mode 100644
index 0000000..709efdb
--- /dev/null
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.animation.TimeInterpolator;
+import android.view.ViewPropertyAnimator.NameValuesHolder;
+
+import com.android.internal.view.animation.FallbackLUTInterpolator;
+
+import java.util.ArrayList;
+
+
+/**
+ * This is a RenderThread driven backend for ViewPropertyAnimator.
+ */
+class ViewPropertyAnimatorRT {
+
+    private final View mView;
+
+    private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1];
+
+    ViewPropertyAnimatorRT(View view) {
+        mView = view;
+    }
+
+    /**
+     * @return true if ViewPropertyAnimatorRT handled the animation,
+     *         false if ViewPropertyAnimator needs to handle it
+     */
+    public boolean startAnimation(ViewPropertyAnimator parent) {
+        cancelAnimators(parent.mPendingAnimations);
+        if (!canHandleAnimator(parent)) {
+            return false;
+        }
+        doStartAnimation(parent);
+        return true;
+    }
+
+    private void doStartAnimation(ViewPropertyAnimator parent) {
+        int size = parent.mPendingAnimations.size();
+
+        long startDelay = parent.getStartDelay();
+        long duration = parent.getDuration();
+        TimeInterpolator interpolator = parent.getInterpolator();
+        if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) {
+            interpolator = new FallbackLUTInterpolator(interpolator, duration);
+        }
+        for (int i = 0; i < size; i++) {
+            NameValuesHolder holder = parent.mPendingAnimations.get(i);
+            int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
+
+            RenderNodeAnimator animator = new RenderNodeAnimator(property, holder.mFromValue + holder.mDeltaValue);
+            animator.setStartDelay(startDelay);
+            animator.setDuration(duration);
+            animator.setInterpolator(interpolator);
+            animator.setTarget(mView);
+            animator.start();
+        }
+
+        parent.mPendingAnimations.clear();
+    }
+
+    private boolean canHandleAnimator(ViewPropertyAnimator parent) {
+        // TODO: Can we eliminate this entirely?
+        // If RenderNode.animatorProperties() can be toggled to point at staging
+        // instead then RNA can be used as the animators for software as well
+        // as the updateListener fallback paths. If this can be toggled
+        // at the top level somehow, combined with requiresUiRedraw, we could
+        // ensure that RT does not self-animate, allowing for safe driving of
+        // the animators from the UI thread using the same mechanisms
+        // ViewPropertyAnimator does, just with everything sitting on a single
+        // animator subsystem instead of multiple.
+
+        if (parent.getUpdateListener() != null) {
+            return false;
+        }
+        if (parent.getListener() != null) {
+            // TODO support
+            return false;
+        }
+        if (!mView.isHardwareAccelerated()) {
+            // TODO handle this maybe?
+            return false;
+        }
+        if (parent.hasActions()) {
+            return false;
+        }
+        // Here goes nothing...
+        return true;
+    }
+
+    private void cancelAnimators(ArrayList<NameValuesHolder> mPendingAnimations) {
+        int size = mPendingAnimations.size();
+        for (int i = 0; i < size; i++) {
+            NameValuesHolder holder = mPendingAnimations.get(i);
+            int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
+            if (mAnimators[property] != null) {
+                mAnimators[property].cancel();
+                mAnimators[property] = null;
+            }
+        }
+    }
+
+}
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 1feb943..06838c9 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -24,10 +24,13 @@
  * Interpolator that builds a lookup table to use. This is a fallback for
  * building a native interpolator from a TimeInterpolator that is not marked
  * with {@link HasNativeInterpolator}
+ *
+ * This implements TimeInterpolator to allow for easier interop with Animators
  */
 @HasNativeInterpolator
-public class FallbackLUTInterpolator implements NativeInterpolatorFactory {
+public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator {
 
+    private TimeInterpolator mSourceInterpolator;
     private final float mLut[];
 
     /**
@@ -35,6 +38,7 @@
      * interpolator creation
      */
     public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) {
+        mSourceInterpolator = interpolator;
         mLut = createLUT(interpolator, duration);
     }
 
@@ -63,4 +67,9 @@
         float[] lut = createLUT(interpolator, duration);
         return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
     }
+
+    @Override
+    public float getInterpolation(float input) {
+        return mSourceInterpolator.getInterpolation(input);
+    }
 }
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index 01eaec4..a3c7b0a 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -100,18 +100,19 @@
     }
     request->buffer_length = length;
 
+    // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
+    request->client_data = (void *)env->NewGlobalRef(thiz);
+
     if (usb_request_queue(request)) {
         if (request->buffer) {
             // free our buffer if usb_request_queue fails
             free(request->buffer);
             request->buffer = NULL;
         }
+        env->DeleteGlobalRef((jobject)request->client_data);
         return false;
-    } else {
-        // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
-        request->client_data = (void *)env->NewGlobalRef(thiz);
-        return true;
     }
+    return true;
 }
 
 static jint
@@ -152,16 +153,17 @@
     }
     request->buffer_length = length;
 
+    // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
+    // we also need this to make sure our native buffer is not deallocated
+    // while IO is active
+    request->client_data = (void *)env->NewGlobalRef(thiz);
+
     if (usb_request_queue(request)) {
         request->buffer = NULL;
+        env->DeleteGlobalRef((jobject)request->client_data);
         return false;
-    } else {
-        // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
-        // we also need this to make sure our native buffer is not deallocated
-        // while IO is active
-        request->client_data = (void *)env->NewGlobalRef(thiz);
-        return true;
     }
+    return true;
 }
 
 static jint
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8dac084..4b03f31 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1669,6 +1669,11 @@
         <enum name="KEYCODE_MEDIA_SLEEP" value="223" />
         <enum name="KEYCODE_MEDIA_WAKEUP" value="224" />
         <enum name="KEYCODE_PAIRING" value="225" />
+        <enum name="KEYCODE_MEDIA_TOP_MENU" value="226" />
+        <enum name="KEYCODE_11" value="227" />
+        <enum name="KEYCODE_12" value="228" />
+        <enum name="KEYCODE_LAST_CHANNEL" value="229" />
+        <enum name="KEYCODE_TV_DATA_SERVICE" value="230" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -4492,7 +4497,7 @@
              RTL (right-to-left). -->
         <attr name="autoMirrored" />
         <!-- Indicates how layer padding should affect the bounds of subsequent layers.
-            The default value is nest. -->
+             The default padding mode value is nest. -->
         <attr name="paddingMode">
             <!-- Nest each layer inside the padding of the previous layer. -->
             <enum name="nest" value="0" />
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 6ea0fae..c966a12 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -83,5 +83,4 @@
   <item type="id" name="current_scene" />
   <item type="id" name="scene_layoutid_cache" />
   <item type="id" name="mask" />
-  <item type="id" name="shared_element" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 44b25f2b..32ce568 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2177,6 +2177,7 @@
   <public type="attr" name="contentInsetEnd" />
   <public type="attr" name="contentInsetLeft" />
   <public type="attr" name="contentInsetRight" />
+  <public type="attr" name="paddingMode" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2186,7 +2187,6 @@
   <public-padding type="id" name="l_resource_pad" end="0x01020040" />
 
   <public type="id" name="mask" />
-  <public type="id" name="shared_element" />
 
   <public-padding type="style" name="l_resource_pad" end="0x01030200" />
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index cad030a..2ce87eb 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -23,15 +23,15 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.AuthAlgorithm;
-import android.net.wifi.WifiConfiguration.IpAssignment;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.ProxySettings;
-import android.net.wifi.WifiEnterpriseConfig;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiEnterpriseConfig;
 
 import java.io.InputStream;
 import java.net.InetAddress;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 91c3093..9692ec0 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -18,12 +18,12 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
 import android.net.NetworkInfo.State;
 import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.IpAssignment;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.ProxySettings;
+import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.PowerManager;
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
index 67203b2..22dce39 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.os.Bundle;
 
+import java.util.Set;
+
 public class BluetoothInstrumentation extends Instrumentation {
 
     private BluetoothTestUtils mUtils = null;
@@ -66,6 +68,8 @@
             getName();
         } else if ("getAddress".equals(command)) {
             getAddress();
+        } else if ("getBondedDevices".equals(command)) {
+            getBondedDevices();
         } else {
             finish(null);
         }
@@ -98,6 +102,16 @@
         finish(mSuccessResult);
     }
 
+    public void getBondedDevices() {
+        Set<BluetoothDevice> devices = getBluetoothAdapter().getBondedDevices();
+        int i = 0;
+        for (BluetoothDevice device : devices) {
+            mSuccessResult.putString(String.format("device-%02d", i), device.getAddress());
+            i++;
+        }
+        finish(mSuccessResult);
+    }
+
     public void finish(Bundle result) {
         if (result == null) {
             result = new Bundle();
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAdvertiseScanDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAdvertiseScanDataTest.java
new file mode 100644
index 0000000..eb6c419
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAdvertiseScanDataTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Unit test cases for {@link BluetoothLeAdvertiseScanData}.
+ * <p>
+ * To run this test, use adb shell am instrument -e class
+ * 'android.bluetooth.BluetoothLeAdvertiseScanDataTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothLeAdvertiseScanDataTest extends TestCase {
+
+    @SmallTest
+    public void testParser() {
+        byte[] scanRecord = new byte[] {
+                0x02, 0x01, 0x1a, // advertising flags
+                0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids
+                0x04, 0x09, 0x50, 0x65, 0x64, // name
+                0x02, 0x0A, (byte) 0xec, // tx power level
+                0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data
+                0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
+                0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
+        };
+        BluetoothLeAdvertiseScanData.ScanRecord data = BluetoothLeAdvertiseScanData.ScanRecord
+                .getParser().parseFromScanRecord(scanRecord);
+        assertEquals(0x1a, data.getAdvertiseFlags());
+        ParcelUuid uuid1 = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+        ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+        assertTrue(data.getServiceUuids().contains(uuid1));
+        assertTrue(data.getServiceUuids().contains(uuid2));
+
+        assertEquals("Ped", data.getLocalName());
+        assertEquals(-20, data.getTxPowerLevel());
+
+        assertEquals(224, data.getManufacturerId());
+        assertArrayEquals(new byte[] {
+                (byte) 0xe0, 0x00, 0x02, 0x15 }, data.getManufacturerSpecificData());
+
+        assertEquals(uuid2, data.getServiceDataUuid());
+        assertArrayEquals(new byte[] {
+                0x0b, 0x11, 0x50, 0x64 }, data.getServiceData());
+    }
+
+    // Assert two byte arrays are equal.
+    private static void assertArrayEquals(byte[] expected, byte[] actual) {
+        if (!Arrays.equals(expected, actual)) {
+            fail("expected:<" + Arrays.toString(expected) +
+                    "> but was:<" + Arrays.toString(actual) + ">");
+        }
+
+    }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScanFilterTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScanFilterTest.java
new file mode 100644
index 0000000..ec35d85
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScanFilterTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothLeScanner.ScanResult;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for Bluetooth LE scan filters.
+ * <p>
+ * To run this test, use adb shell am instrument -e class
+ * 'android.bluetooth.BluetoothLeScanFilterTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothLeScanFilterTest extends TestCase {
+
+    private static final String DEVICE_MAC = "01:02:03:04:05:AB";
+    private ScanResult mScanResult;
+    private BluetoothLeScanFilter.Builder mFilterBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        byte[] scanRecord = new byte[] {
+                0x02, 0x01, 0x1a, // advertising flags
+                0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids
+                0x04, 0x09, 0x50, 0x65, 0x64, // name
+                0x02, 0x0A, (byte) 0xec, // tx power level
+                0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data
+                0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
+                0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
+        };
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(DEVICE_MAC);
+        mScanResult = new ScanResult(device, scanRecord, -10, 1397545200000000L);
+        mFilterBuilder = BluetoothLeScanFilter.newBuilder();
+    }
+
+    @SmallTest
+    public void testNameFilter() {
+        BluetoothLeScanFilter filter = mFilterBuilder.name("Ped").build();
+        assertTrue("name filter fails", filter.matches(mScanResult));
+
+        filter = mFilterBuilder.name("Pem").build();
+        assertFalse("name filter fails", filter.matches(mScanResult));
+
+    }
+
+    @SmallTest
+    public void testDeviceFilter() {
+        BluetoothLeScanFilter filter = mFilterBuilder.macAddress(DEVICE_MAC).build();
+        assertTrue("device filter fails", filter.matches(mScanResult));
+
+        filter = mFilterBuilder.macAddress("11:22:33:44:55:66").build();
+        assertFalse("device filter fails", filter.matches(mScanResult));
+    }
+
+    @SmallTest
+    public void testServiceUuidFilter() {
+        BluetoothLeScanFilter filter = mFilterBuilder.serviceUuid(
+                ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB")).build();
+        assertTrue("uuid filter fails", filter.matches(mScanResult));
+
+        filter = mFilterBuilder.serviceUuid(
+                ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build();
+        assertFalse("uuid filter fails", filter.matches(mScanResult));
+
+        filter = mFilterBuilder
+                .serviceUuid(ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"))
+                .serviceUuidMask(ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF"))
+                .build();
+        assertTrue("uuid filter fails", filter.matches(mScanResult));
+    }
+
+    @SmallTest
+    public void testServiceDataFilter() {
+        byte[] serviceData = new byte[] {
+                0x0b, 0x11, 0x50, 0x64 };
+        BluetoothLeScanFilter filter = mFilterBuilder.serviceData(serviceData).build();
+        assertTrue("service data filter fails", filter.matches(mScanResult));
+
+        byte[] nonMatchData = new byte[] {
+                0x0b, 0x01, 0x50, 0x64 };
+        filter = mFilterBuilder.serviceData(nonMatchData).build();
+        assertFalse("service data filter fails", filter.matches(mScanResult));
+
+        byte[] mask = new byte[] {
+                (byte) 0xFF, (byte) 0x00, (byte) 0xFF, (byte) 0xFF };
+        filter = mFilterBuilder.serviceData(nonMatchData).serviceDataMask(mask).build();
+        assertTrue("partial service data filter fails", filter.matches(mScanResult));
+    }
+
+    @SmallTest
+    public void testManufacturerSpecificData() {
+        byte[] manufacturerData = new byte[] {
+                (byte) 0xE0, 0x00, 0x02, 0x15 };
+        int manufacturerId = 224;
+        BluetoothLeScanFilter filter =
+                mFilterBuilder.manufacturerData(manufacturerId, manufacturerData).build();
+        assertTrue("manufacturerData filter fails", filter.matches(mScanResult));
+
+        byte[] nonMatchData = new byte[] {
+                (byte) 0xF0, 0x00, 0x02, 0x15 };
+        filter = mFilterBuilder.manufacturerData(manufacturerId, nonMatchData).build();
+        assertFalse("manufacturerData filter fails", filter.matches(mScanResult));
+
+        byte[] mask = new byte[] {
+                (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+        };
+        filter = mFilterBuilder.manufacturerData(manufacturerId, nonMatchData)
+                .manufacturerDataMask(mask).build();
+        assertTrue("partial manufacturerData filter fails", filter.matches(mScanResult));
+    }
+
+    @SmallTest
+    public void testReadWriteParcel() {
+        BluetoothLeScanFilter filter = mFilterBuilder.build();
+        testReadWriteParcelForFilter(filter);
+
+        filter = mFilterBuilder.name("Ped").build();
+        testReadWriteParcelForFilter(filter);
+
+        filter = mFilterBuilder.macAddress("11:22:33:44:55:66").build();
+        testReadWriteParcelForFilter(filter);
+
+        filter = mFilterBuilder.serviceUuid(
+                ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build();
+        testReadWriteParcelForFilter(filter);
+
+        filter = mFilterBuilder.serviceUuidMask(
+                ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF")).build();
+        testReadWriteParcelForFilter(filter);
+
+        byte[] serviceData = new byte[] {
+                0x0b, 0x11, 0x50, 0x64 };
+
+        filter = mFilterBuilder.serviceData(serviceData).build();
+        testReadWriteParcelForFilter(filter);
+
+        byte[] serviceDataMask = new byte[] {
+                (byte) 0xFF, (byte) 0x00, (byte) 0xFF, (byte) 0xFF };
+        filter = mFilterBuilder.serviceDataMask(serviceDataMask).build();
+        testReadWriteParcelForFilter(filter);
+
+        byte[] manufacturerData = new byte[] {
+                (byte) 0xE0, 0x00, 0x02, 0x15 };
+        int manufacturerId = 224;
+        filter = mFilterBuilder.manufacturerData(manufacturerId, manufacturerData).build();
+        testReadWriteParcelForFilter(filter);
+
+        byte[] manufacturerDataMask = new byte[] {
+                (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+        };
+        filter = mFilterBuilder.manufacturerDataMask(manufacturerDataMask).build();
+        testReadWriteParcelForFilter(filter);
+    }
+
+    private void testReadWriteParcelForFilter(BluetoothLeScanFilter filter) {
+        Parcel parcel = Parcel.obtain();
+        filter.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        BluetoothLeScanFilter filterFromParcel =
+                BluetoothLeScanFilter.CREATOR.createFromParcel(parcel);
+        System.out.println(filterFromParcel);
+        assertEquals(filter, filterFromParcel);
+    }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScannerTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScannerTest.java
new file mode 100644
index 0000000..8064ba8
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeScannerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothLeScanner.ScanResult;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for Bluetooth LE scans.
+ * <p>
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothLeScannerTest'
+ * -w 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothLeScannerTest extends TestCase {
+
+    /**
+     * Test read and write parcel of ScanResult
+     */
+    @SmallTest
+    public void testScanResultParceling() {
+        BluetoothDevice device = new BluetoothDevice("01:02:03:04:05:06");
+        byte[] scanRecord = new byte[] {
+                1, 2, 3 };
+        int rssi = -10;
+        long timestampMicros = 10000L;
+
+        ScanResult result = new ScanResult(device, scanRecord, rssi, timestampMicros);
+        Parcel parcel = Parcel.obtain();
+        result.writeToParcel(parcel, 0);
+        // Need to reset parcel data position to the beginning.
+        parcel.setDataPosition(0);
+        ScanResult resultFromParcel = ScanResult.CREATOR.createFromParcel(parcel);
+        assertEquals(result, resultFromParcel);
+    }
+
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
index 0f3ea0e..536d722 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
@@ -47,4 +47,20 @@
         assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
                 BluetoothUuid.parseUuidFrom(uuid128));
     }
+
+    @SmallTest
+    public void testUuidType() {
+        assertTrue(BluetoothUuid.is16BitUuid(
+                ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB")));
+        assertFalse(BluetoothUuid.is32BitUuid(
+                ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB")));
+
+        assertFalse(BluetoothUuid.is16BitUuid(
+                ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB")));
+        assertTrue(BluetoothUuid.is32BitUuid(
+                ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB")));
+        assertFalse(BluetoothUuid.is32BitUuid(
+                ParcelUuid.fromString("FE33110B-1000-1000-8000-00805F9B34FB")));
+
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 951add9..3ef1d68 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -513,13 +513,12 @@
     }
 
     /**
-     * Indicates whether this view will change its appearance based on state.
-     * Clients can use this to determine whether it is necessary to calculate
-     * their state and call setState.
+     * Indicates whether this drawable will change its appearance based on
+     * state. Clients can use this to determine whether it is necessary to
+     * calculate their state and call setState.
      *
-     * @return True if this view changes its appearance based on state, false
-     *         otherwise.
-     *
+     * @return True if this drawable changes its appearance based on state,
+     *         false otherwise.
      * @see #setState(int[])
      */
     public boolean isStateful() {
@@ -1010,6 +1009,11 @@
         return createFromXmlInnerThemed(r, parser, attrs, null);
     }
 
+    /**
+     * Create a themed drawable from inside an XML document. Called on a parser
+     * positioned at a tag in an XML document, tries to create a Drawable from
+     * that tag. Returns null if the tag is not a valid drawable.
+     */
     public static Drawable createFromXmlInnerThemed(Resources r, XmlPullParser parser,
             AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException {
         final Drawable drawable;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 373d894..f446000 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -38,10 +38,12 @@
  * order, so the element with the largest index will be drawn on top.
  * <p>
  * It can be defined in an XML file with the <code>&lt;layer-list></code> element.
- * Each Drawable in the layer is defined in a nested <code>&lt;item></code>. For more
- * information, see the guide to <a
- * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
+ * Each Drawable in the layer is defined in a nested <code>&lt;item></code>.
+ * <p>
+ * For more information, see the guide to
+ * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
  *
+ * @attr ref android.R.styleable#LayerDrawable_paddingMode
  * @attr ref android.R.styleable#LayerDrawableItem_left
  * @attr ref android.R.styleable#LayerDrawableItem_top
  * @attr ref android.R.styleable#LayerDrawableItem_right
@@ -53,10 +55,16 @@
     /**
      * Padding mode used to nest each layer inside the padding of the previous
      * layer.
+     *
+     * @see #setPaddingMode(int)
      */
     public static final int PADDING_MODE_NEST = 0;
 
-    /** Padding mode used to stack each layer directly atop the previous layer. */
+    /**
+     * Padding mode used to stack each layer directly atop the previous layer.
+     *
+     * @see #setPaddingMode(int)
+     */
     public static final int PADDING_MODE_STACK = 1;
 
     LayerState mLayerState;
@@ -127,9 +135,8 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(
-                r, theme, attrs, R.styleable.LayerDrawable);
-        inflateStateFromTypedArray(a);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable);
+        updateStateFromTypedArray(a);
         a.recycle();
 
         inflateLayers(r, parser, attrs, theme);
@@ -141,25 +148,19 @@
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void inflateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) {
         final LayerState state = mLayerState;
 
         // Extract the theme attributes, if any.
         final int[] themeAttrs = a.extractThemeAttrs();
         state.mThemeAttrs = themeAttrs;
 
-        if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawable_opacity] == 0) {
-            mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, PixelFormat.UNKNOWN);
-        }
+        mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, mOpacityOverride);
 
-        if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawable_autoMirrored] == 0) {
-            state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored, false);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawableItem_drawable] == 0) {
-            state.mPaddingMode = a.getInteger(
-                    R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST);
-        }
+        state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored,
+                state.mAutoMirrored);
+        state.mPaddingMode = a.getInteger(R.styleable.LayerDrawable_paddingMode,
+                state.mPaddingMode);
     }
 
     /**
@@ -181,9 +182,9 @@
                 continue;
             }
 
-            a = obtainAttributes(
-                    r, theme, attrs, R.styleable.LayerDrawableItem);
+            a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem);
 
+            final int[] themeAttrs = a.extractThemeAttrs();
             final int left = a.getDimensionPixelOffset(
                     R.styleable.LayerDrawableItem_left, 0);
             final int top = a.getDimensionPixelOffset(
@@ -197,7 +198,6 @@
             final int id = a.getResourceId(
                     R.styleable.LayerDrawableItem_id, View.NO_ID);
 
-            // TODO: Cache typed array, if necessary.
             a.recycle();
 
             final Drawable dr;
@@ -214,7 +214,7 @@
                 dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
             }
 
-            addLayer(dr, id, left, top, right, bottom);
+            addLayer(dr, themeAttrs, id, left, top, right, bottom);
         }
     }
 
@@ -224,7 +224,7 @@
 
         final LayerState state = mLayerState;
         if (state == null) {
-            throw new RuntimeException("Can't apply theme to <layer-list> with no constant state");
+            return;
         }
 
         final int[] themeAttrs = state.mThemeAttrs;
@@ -239,9 +239,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            final Drawable layer = array[i].mDrawable;
-            if (layer.canApplyTheme()) {
-                layer.applyTheme(t);
+            final ChildDrawable layer = array[i];
+            final Drawable d = layer.mDrawable;
+            if (d.canApplyTheme()) {
+                d.applyTheme(t);
             }
         }
 
@@ -249,26 +250,6 @@
         onStateChange(getState());
     }
 
-    /**
-     * Updates the constant state from the values in the typed array.
-     */
-    private void updateStateFromTypedArray(TypedArray a) {
-        final LayerState state = mLayerState;
-
-        if (a.hasValue(R.styleable.LayerDrawable_opacity)) {
-            mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, PixelFormat.UNKNOWN);
-        }
-
-        if (a.hasValue(R.styleable.LayerDrawable_autoMirrored)) {
-            state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored, false);
-        }
-
-        if (a.hasValue(R.styleable.LayerDrawableItem_drawable)) {
-            state.mPaddingMode = a.getInteger(
-                    R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST);
-        }
-    }
-
     @Override
     public boolean canApplyTheme() {
         final LayerState state = mLayerState;
@@ -283,14 +264,15 @@
         final ChildDrawable[] array = state.mChildren;
         final int N = state.mNum;
         for (int i = 0; i < N; i++) {
-            if (array[i].mDrawable.canApplyTheme()) {
+            final ChildDrawable layer = array[i];
+            if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
                 return true;
             }
         }
 
         return false;
     }
-    
+
     /**
      * @hide
      */
@@ -315,13 +297,15 @@
      * Add a new layer to this drawable. The new layer is identified by an id.
      *
      * @param layer The drawable to add as a layer.
+     * @param themeAttrs Theme attributes extracted from the layer.
      * @param id The id of the new layer.
      * @param left The left padding of the new layer.
      * @param top The top padding of the new layer.
      * @param right The right padding of the new layer.
      * @param bottom The bottom padding of the new layer.
      */
-    private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) {
+    private void addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right,
+            int bottom) {
         final LayerState st = mLayerState;
         final int N = st.mChildren != null ? st.mChildren.length : 0;
         final int i = st.mNum;
@@ -339,6 +323,7 @@
         final ChildDrawable childDrawable = new ChildDrawable();
         st.mChildren[i] = childDrawable;
         childDrawable.mId = id;
+        childDrawable.mThemeAttrs = themeAttrs;
         childDrawable.mDrawable = layer;
         childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
         childDrawable.mInsetL = left;
@@ -471,8 +456,14 @@
      *
      * @param mode padding mode, one of:
      *            <ul>
-     *            <li>{@link #PADDING_MODE_NEST} <li>{@link #PADDING_MODE_STACK}
+     *            <li>{@link #PADDING_MODE_NEST} to nest each layer inside the
+     *            padding of the previous layer
+     *            <li>{@link #PADDING_MODE_STACK} to stack each layer directly
+     *            atop the previous layer
      *            </ul>
+     *
+     * @see #getPaddingMode()
+     * @attr ref android.R.styleable#LayerDrawable_paddingMode
      */
     public void setPaddingMode(int mode) {
         if (mLayerState.mPaddingMode != mode) {
@@ -482,7 +473,9 @@
 
     /**
      * @return the current padding mode
+     *
      * @see #setPaddingMode(int)
+     * @attr ref android.R.styleable#LayerDrawable_paddingMode
      */
     public int getPaddingMode() {
       return mLayerState.mPaddingMode;
@@ -905,7 +898,7 @@
         private boolean mHaveIsStateful;
         private boolean mIsStateful;
 
-        private boolean mAutoMirrored;
+        private boolean mAutoMirrored = false;
 
         private int mPaddingMode = PADDING_MODE_NEST;
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index edf1091..5f9d1cd 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -145,6 +145,9 @@
      * Sets the start angle for rotation.
      *
      * @param fromDegrees Starting angle in degrees
+     *
+     * @see #getFromDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
     public void setFromDegrees(float fromDegrees) {
         if (mState.mFromDegrees != fromDegrees) {
@@ -155,6 +158,9 @@
 
     /**
      * @return The starting angle for rotation in degrees
+     *
+     * @see #setFromDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
     public float getFromDegrees() {
         return mState.mFromDegrees;
@@ -164,6 +170,9 @@
      * Sets the end angle for rotation.
      *
      * @param toDegrees Ending angle in degrees
+     *
+     * @see #getToDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
      */
     public void setToDegrees(float toDegrees) {
         if (mState.mToDegrees != toDegrees) {
@@ -174,6 +183,9 @@
 
     /**
      * @return The ending angle for rotation in degrees
+     *
+     * @see #setToDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
      */
     public float getToDegrees() {
         return mState.mToDegrees;
@@ -186,7 +198,9 @@
      *            relative, the position represents a fraction of the drawable
      *            width. Otherwise, the position represents an absolute value in
      *            pixels.
+     *
      * @see #setPivotXRelative(boolean)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
      */
     public void setPivotX(float pivotX) {
         if (mState.mPivotX == pivotX) {
@@ -197,7 +211,9 @@
 
     /**
      * @return X position around which to rotate
+     *
      * @see #setPivotX(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
      */
     public float getPivotX() {
         return mState.mPivotX;
@@ -209,6 +225,8 @@
      *
      * @param relative True if the X pivot represents a fraction of the drawable
      *            width, or false if it represents an absolute value in pixels
+     *
+     * @see #isPivotXRelative()
      */
     public void setPivotXRelative(boolean relative) {
         if (mState.mPivotXRel == relative) {
@@ -220,6 +238,7 @@
     /**
      * @return True if the X pivot represents a fraction of the drawable width,
      *         or false if it represents an absolute value in pixels
+     *
      * @see #setPivotXRelative(boolean)
      */
     public boolean isPivotXRelative() {
@@ -233,7 +252,9 @@
      *            relative, the position represents a fraction of the drawable
      *            height. Otherwise, the position represents an absolute value
      *            in pixels.
-     * @see #setPivotYRelative(boolean)
+     *
+     * @see #getPivotY()
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
      */
     public void setPivotY(float pivotY) {
         if (mState.mPivotY == pivotY) {
@@ -244,7 +265,9 @@
 
     /**
      * @return Y position around which to rotate
+     *
      * @see #setPivotY(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
      */
     public float getPivotY() {
         return mState.mPivotY;
@@ -256,6 +279,8 @@
      *
      * @param relative True if the Y pivot represents a fraction of the drawable
      *            height, or false if it represents an absolute value in pixels
+     *
+     * @see #isPivotYRelative()
      */
     public void setPivotYRelative(boolean relative) {
         if (mState.mPivotYRel == relative) {
@@ -267,6 +292,7 @@
     /**
      * @return True if the Y pivot represents a fraction of the drawable height,
      *         or false if it represents an absolute value in pixels
+     *
      * @see #setPivotYRelative(boolean)
      */
     public boolean isPivotYRelative() {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3a3f76d..575667d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2557,60 +2557,191 @@
     // class is not used by other parts of the framework, which instead use definitions and methods
     // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
 
-    /** {@hide} The audio output device code for the small speaker at the front of the device used
+    /** @hide
+     *  The audio output device code for the small speaker at the front of the device used
      *  when placing calls.  Does not refer to an in-ear headphone without attached microphone,
      *  such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
      *  {@link #DEVICE_OUT_WIRED_HEADPHONE}.
      */
     public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
-    /** {@hide} The audio output device code for the built-in speaker */
+    /** @hide
+     *  The audio output device code for the built-in speaker */
     public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
-    /** {@hide} The audio output device code for a wired headset with attached microphone */
+    /** @hide
+     * The audio output device code for a wired headset with attached microphone */
     public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
-    /** {@hide} The audio output device code for a wired headphone without attached microphone */
+    /** @hide
+     * The audio output device code for a wired headphone without attached microphone */
     public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
-    /** {@hide} The audio output device code for generic Bluetooth SCO, for voice */
+    /** @hide
+     * The audio output device code for generic Bluetooth SCO, for voice */
     public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-    /** {@hide} The audio output device code for Bluetooth SCO Headset Profile (HSP) and
-     *  Hands-Free Profile (HFP), for voice
+    /** @hide
+     * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
+     * Hands-Free Profile (HFP), for voice
      */
     public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-    /** {@hide} The audio output device code for Bluetooth SCO car audio, for voice */
+    /** @hide
+     * The audio output device code for Bluetooth SCO car audio, for voice */
     public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-    /** {@hide} The audio output device code for generic Bluetooth A2DP, for music */
+    /** @hide
+     * The audio output device code for generic Bluetooth A2DP, for music */
     public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
-    /** {@hide} The audio output device code for Bluetooth A2DP headphones, for music */
+    /** @hide
+     * The audio output device code for Bluetooth A2DP headphones, for music */
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
-    /** {@hide} The audio output device code for Bluetooth A2DP external speaker, for music */
+    /** @hide
+     * The audio output device code for Bluetooth A2DP external speaker, for music */
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
-    /** {@hide} The audio output device code for S/PDIF or HDMI */
+    /** @hide
+     * The audio output device code for S/PDIF (legacy) or HDMI
+     * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
     public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
-    /** {@hide} The audio output device code for an analog wired headset attached via a
+    /** @hide
+     * The audio output device code for HDMI */
+    public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
+    /** @hide
+     * The audio output device code for an analog wired headset attached via a
      *  docking station
      */
     public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
-    /** {@hide} The audio output device code for a digital wired headset attached via a
+    /** @hide
+     * The audio output device code for a digital wired headset attached via a
      *  docking station
      */
     public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
-    /** {@hide} The audio output device code for a USB audio accessory. The accessory is in USB host
+    /** @hide
+     * The audio output device code for a USB audio accessory. The accessory is in USB host
      * mode and the Android device in USB device mode
      */
     public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
-    /** {@hide} The audio output device code for a USB audio device. The device is in USB device
+    /** @hide
+     * The audio output device code for a USB audio device. The device is in USB device
      * mode and the Android device in USB host mode
      */
     public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
-    /** {@hide} This is not used as a returned value from {@link #getDevicesForStream}, but could be
+    /** @hide
+     * The audio output device code for projection output.
+     */
+    public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+    /** @hide
+     * The audio output device code the telephony voice TX path.
+     */
+    public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
+    /** @hide
+     * The audio output device code for an analog jack with line impedance detected.
+     */
+    public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
+    /** @hide
+     * The audio output device code for HDMI Audio Return Channel.
+     */
+    public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
+    /** @hide
+     * The audio output device code for S/PDIF digital connection.
+     */
+    public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
+    /** @hide
+     * The audio output device code for built-in FM transmitter.
+     */
+    public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
+    /** @hide
+     * This is not used as a returned value from {@link #getDevicesForStream}, but could be
      *  used in the future in a set method to select whatever default device is chosen by the
      *  platform-specific implementation.
      */
     public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
 
+    /** @hide
+     * The audio input device code for default built-in microphone
+     */
+    public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
+    /** @hide
+     * The audio input device code for a Bluetooth SCO headset
+     */
+    public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
+                                    AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    /** @hide
+     * The audio input device code for wired headset microphone
+     */
+    public static final int DEVICE_IN_WIRED_HEADSET =
+                                    AudioSystem.DEVICE_IN_WIRED_HEADSET;
+    /** @hide
+     * The audio input device code for HDMI
+     */
+    public static final int DEVICE_IN_HDMI =
+                                    AudioSystem.DEVICE_IN_HDMI;
+    /** @hide
+     * The audio input device code for telephony voice RX path
+     */
+    public static final int DEVICE_IN_TELEPHONY_RX =
+                                    AudioSystem.DEVICE_IN_TELEPHONY_RX;
+    /** @hide
+     * The audio input device code for built-in microphone pointing to the back
+     */
+    public static final int DEVICE_IN_BACK_MIC =
+                                    AudioSystem.DEVICE_IN_BACK_MIC;
+    /** @hide
+     * The audio input device code for analog from a docking station
+     */
+    public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
+                                    AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
+    /** @hide
+     * The audio input device code for digital from a docking station
+     */
+    public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
+                                    AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
+    /** @hide
+     * The audio input device code for a USB audio accessory. The accessory is in USB host
+     * mode and the Android device in USB device mode
+     */
+    public static final int DEVICE_IN_USB_ACCESSORY =
+                                    AudioSystem.DEVICE_IN_USB_ACCESSORY;
+    /** @hide
+     * The audio input device code for a USB audio device. The device is in USB device
+     * mode and the Android device in USB host mode
+     */
+    public static final int DEVICE_IN_USB_DEVICE =
+                                    AudioSystem.DEVICE_IN_USB_DEVICE;
+    /** @hide
+     * The audio input device code for a FM radio tuner
+     */
+    public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
+    /** @hide
+     * The audio input device code for a TV tuner
+     */
+    public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
+    /** @hide
+     * The audio input device code for an analog jack with line impedance detected
+     */
+    public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
+    /** @hide
+     * The audio input device code for a S/PDIF digital connection
+     */
+    public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
+
+    /**
+     * Return true if the device code corresponds to an output device.
+     * @hide
+     */
+    public static boolean isOutputDevice(int device)
+    {
+        return (device & AudioSystem.DEVICE_BIT_IN) == 0;
+    }
+
+    /**
+     * Return true if the device code corresponds to an input device.
+     * @hide
+     */
+    public static boolean isInputDevice(int device)
+    {
+        return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
+    }
+
+
     /**
      * Return the enabled devices for the specified output stream type.
      *
@@ -2635,9 +2766,17 @@
      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP},
      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
-     *            {@link #DEVICE_OUT_AUX_DIGITAL},
+     *            {@link #DEVICE_OUT_HDMI},
      *            {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
      *            {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
+     *            {@link #DEVICE_OUT_USB_ACCESSORY}.
+     *            {@link #DEVICE_OUT_USB_DEVICE}.
+     *            {@link #DEVICE_OUT_REMOTE_SUBMIX}.
+     *            {@link #DEVICE_OUT_TELEPHONY_TX}.
+     *            {@link #DEVICE_OUT_LINE}.
+     *            {@link #DEVICE_OUT_HDMI_ARC}.
+     *            {@link #DEVICE_OUT_SPDIF}.
+     *            {@link #DEVICE_OUT_FM}.
      *            {@link #DEVICE_OUT_DEFAULT} is not used here.
      *
      * The implementation may support additional device codes beyond those listed, so
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index bb8cfa6..6e623a5 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -423,7 +423,7 @@
     public final static int STREAM_REMOTE_MUSIC = -200;
 
     // Devices for which the volume is fixed and VolumePanel slider should be disabled
-    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL |
+    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_ALL_USB;
@@ -2895,7 +2895,7 @@
 
         public String getSettingNameForDevice(int device) {
             String name = mVolumeIndexSettingName;
-            String suffix = AudioSystem.getDeviceName(device);
+            String suffix = AudioSystem.getOutputDeviceName(device);
             if (suffix.isEmpty()) {
                 return name;
             }
@@ -3935,7 +3935,7 @@
     // sent if none of these devices is connected.
     int mBecomingNoisyIntentDevices =
             AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
-            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL |
+            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_ALL_USB;
 
@@ -3992,7 +3992,7 @@
         } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
             connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
             intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
-        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
+        } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
             connType = AudioRoutesInfo.MAIN_HDMI;
             intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
         }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 5ddb198..0c45443 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -234,11 +234,17 @@
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
     public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+    public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL;
     public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
     public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
     public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
     public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
     public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
+    public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000;
+    public static final int DEVICE_OUT_LINE = 0x20000;
+    public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
+    public static final int DEVICE_OUT_SPDIF = 0x80000;
+    public static final int DEVICE_OUT_FM = 0x100000;
 
     public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
 
@@ -252,12 +258,17 @@
                                               DEVICE_OUT_BLUETOOTH_A2DP |
                                               DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                                               DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                              DEVICE_OUT_AUX_DIGITAL |
+                                              DEVICE_OUT_HDMI |
                                               DEVICE_OUT_ANLG_DOCK_HEADSET |
                                               DEVICE_OUT_DGTL_DOCK_HEADSET |
                                               DEVICE_OUT_USB_ACCESSORY |
                                               DEVICE_OUT_USB_DEVICE |
                                               DEVICE_OUT_REMOTE_SUBMIX |
+                                              DEVICE_OUT_TELEPHONY_TX |
+                                              DEVICE_OUT_LINE |
+                                              DEVICE_OUT_HDMI_ARC |
+                                              DEVICE_OUT_SPDIF |
+                                              DEVICE_OUT_FM |
                                               DEVICE_OUT_DEFAULT);
     public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
                                                    DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -275,13 +286,20 @@
     public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8;
     public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10;
     public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20;
+    public static final int DEVICE_IN_HDMI = DEVICE_IN_AUX_DIGITAL;
     public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40;
+    public static final int DEVICE_IN_TELEPHONY_RX = DEVICE_IN_VOICE_CALL;
     public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80;
     public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100;
     public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200;
     public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400;
     public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800;
     public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000;
+    public static final int DEVICE_IN_FM_TUNER = DEVICE_BIT_IN | 0x2000;
+    public static final int DEVICE_IN_TV_TUNER = DEVICE_BIT_IN | 0x4000;
+    public static final int DEVICE_IN_LINE = DEVICE_BIT_IN | 0x8000;
+    public static final int DEVICE_IN_SPDIF = DEVICE_BIT_IN | 0x10000;
+
     public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
 
     public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
@@ -289,14 +307,18 @@
                                              DEVICE_IN_BUILTIN_MIC |
                                              DEVICE_IN_BLUETOOTH_SCO_HEADSET |
                                              DEVICE_IN_WIRED_HEADSET |
-                                             DEVICE_IN_AUX_DIGITAL |
-                                             DEVICE_IN_VOICE_CALL |
+                                             DEVICE_IN_HDMI |
+                                             DEVICE_IN_TELEPHONY_RX |
                                              DEVICE_IN_BACK_MIC |
                                              DEVICE_IN_REMOTE_SUBMIX |
                                              DEVICE_IN_ANLG_DOCK_HEADSET |
                                              DEVICE_IN_DGTL_DOCK_HEADSET |
                                              DEVICE_IN_USB_ACCESSORY |
                                              DEVICE_IN_USB_DEVICE |
+                                             DEVICE_IN_FM_TUNER |
+                                             DEVICE_IN_TV_TUNER |
+                                             DEVICE_IN_LINE |
+                                             DEVICE_IN_SPDIF |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
     public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -318,13 +340,19 @@
     public static final String DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME = "bt_a2dp_hp";
     public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk";
     public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital";
+    public static final String DEVICE_OUT_HDMI_NAME = "hdmi";
     public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock";
     public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock";
     public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory";
     public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device";
     public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix";
+    public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx";
+    public static final String DEVICE_OUT_LINE_NAME = "line";
+    public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc";
+    public static final String DEVICE_OUT_SPDIF_NAME = "spdif";
+    public static final String DEVICE_OUT_FM_NAME = "fm_transmitter";
 
-    public static String getDeviceName(int device)
+    public static String getOutputDeviceName(int device)
     {
         switch(device) {
         case DEVICE_OUT_EARPIECE:
@@ -347,8 +375,8 @@
             return DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME;
         case DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
             return DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME;
-        case DEVICE_OUT_AUX_DIGITAL:
-            return DEVICE_OUT_AUX_DIGITAL_NAME;
+        case DEVICE_OUT_HDMI:
+            return DEVICE_OUT_HDMI_NAME;
         case DEVICE_OUT_ANLG_DOCK_HEADSET:
             return DEVICE_OUT_ANLG_DOCK_HEADSET_NAME;
         case DEVICE_OUT_DGTL_DOCK_HEADSET:
@@ -359,12 +387,23 @@
             return DEVICE_OUT_USB_DEVICE_NAME;
         case DEVICE_OUT_REMOTE_SUBMIX:
             return DEVICE_OUT_REMOTE_SUBMIX_NAME;
+        case DEVICE_OUT_TELEPHONY_TX:
+            return DEVICE_OUT_TELEPHONY_TX_NAME;
+        case DEVICE_OUT_LINE:
+            return DEVICE_OUT_LINE_NAME;
+        case DEVICE_OUT_HDMI_ARC:
+            return DEVICE_OUT_HDMI_ARC_NAME;
+        case DEVICE_OUT_SPDIF:
+            return DEVICE_OUT_SPDIF_NAME;
+        case DEVICE_OUT_FM:
+            return DEVICE_OUT_FM_NAME;
         case DEVICE_OUT_DEFAULT:
         default:
             return "";
         }
     }
 
+
     // phone state, match audio_mode???
     public static final int PHONE_STATE_OFFCALL = 0;
     public static final int PHONE_STATE_RINGING = 1;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 37f45c2..26ae3cc 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -407,6 +407,19 @@
     }
 
     /**
+     * Get a {@link MediaSession} associated with this RCC. It will only have a
+     * session while it is registered with
+     * {@link AudioManager#registerRemoteControlClient}. The session returned
+     * should not be modified directly by the application but may be used with
+     * other APIs that require a session.
+     *
+     * @return A media session object or null.
+     */
+    public MediaSession getMediaSession() {
+        return mSession;
+    }
+
+    /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
      * on which you set the metadata for the RemoteControlClient instance. Once all the information
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 84028b7..d21b442 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -351,7 +351,7 @@
     if (!data) {
         return NULL;
     }
-    long len = *((long*)data);
+    jsize len = *((uint32_t*)data);
 
     jbyteArray array = env->NewByteArray(len);
     if (array != NULL) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 2d17b7b..aae92e8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -149,14 +149,16 @@
         if (mLockPatternUtils.checkPassword(entry)) {
             mCallback.reportUnlockAttempt(true);
             mCallback.dismiss(true);
-        } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
-            // to avoid accidental lockout, only count attempts that are long enough to be a
-            // real password. This may require some tweaking.
-            mCallback.reportUnlockAttempt(false);
-            int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
-            if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
-                long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
-                handleAttemptLockout(deadline);
+        } else {
+            if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
+                // to avoid accidental lockout, only count attempts that are long enough to be a
+                // real password. This may require some tweaking.
+                mCallback.reportUnlockAttempt(false);
+                int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
+                if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
+                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+                    handleAttemptLockout(deadline);
+                }
             }
             mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 909c32e..286921e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 102;
+    private static final int DATABASE_VERSION = 103;
 
     private Context mContext;
     private int mUserHandle;
@@ -1632,6 +1632,34 @@
             upgradeVersion = 102;
         }
 
+        if (upgradeVersion == 102) {
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                // The INSTALL_NON_MARKET_APPS setting is becoming per-user rather
+                // than device-global.
+                if (mUserHandle == UserHandle.USER_OWNER) {
+                    // In the owner user, the global table exists so we can migrate the
+                    // entry from there to the secure table, preserving its value.
+                    String[] globalToSecure = {
+                            Settings.Secure.INSTALL_NON_MARKET_APPS
+                    };
+                    moveSettingsToNewTable(db, TABLE_GLOBAL, TABLE_SECURE, globalToSecure, true);
+                } else {
+                    // Secondary users' dbs don't have the global table, so institute the
+                    // default.
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+                            + " VALUES(?,?);");
+                    loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
+                            R.bool.def_install_non_market_apps);
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 103;
+        }
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2191,6 +2219,9 @@
             loadStringSetting(stmt, Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
                         R.string.def_immersive_mode_confirmations);
 
+            loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
+                    R.bool.def_install_non_market_apps);
+
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2289,9 +2320,6 @@
             loadBooleanSetting(stmt, Settings.Global.NETSTATS_ENABLED,
                     R.bool.def_netstats_enabled);
 
-            loadBooleanSetting(stmt, Settings.Global.INSTALL_NON_MARKET_APPS,
-                    R.bool.def_install_non_market_apps);
-
             loadBooleanSetting(stmt, Settings.Global.USB_MASS_STORAGE_ENABLED,
                     R.bool.def_usb_mass_storage_enabled);
 
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index b24d4ad..85de645 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -23,6 +23,7 @@
         android:background="@drawable/qs_panel_background" >
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
+            android:background="#0000"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index a68ad2f..97051ff 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -22,21 +22,6 @@
         android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <com.android.systemui.recents.views.TaskInfoView
-        android:id="@+id/task_view_info_pane"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="invisible"
-        android:background="@color/recents_task_bar_default_background_color">
-        <Button
-            android:id="@+id/task_view_app_info_button"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="20dp"
-            android:layout_marginEnd="20dp"
-            android:layout_gravity="top|center_horizontal"
-            android:text="@string/recents_app_info_button_label" />
-    </com.android.systemui.recents.views.TaskInfoView>
     <com.android.systemui.recents.views.TaskBarView
         android:id="@+id/task_view_bar"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 2837cd6..5fabd3e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -27,7 +27,7 @@
     <Button
         android:id="@+id/veto"
         android:layout_width="48dp"
-        android:layout_height="match_parent"
+        android:layout_height="0dp"
         android:gravity="end"
         android:layout_marginEnd="-80dp"
         android:background="@null"
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 6df2a19..ffd64d4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,10 +64,12 @@
                 mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
                 mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
                 mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
-                Console.log(Constants.Log.App.RecentsComponent,
-                        "[RecentsComponent|RecentsMessageHandler|handleMessage]",
-                        "singleTaskRect: " + mSingleCountFirstTaskRect +
-                        " multipleTaskRect: " + mMultipleCountFirstTaskRect);
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.RecentsComponent,
+                            "[RecentsComponent|RecentsMessageHandler|handleMessage]",
+                            "singleTaskRect: " + mSingleCountFirstTaskRect +
+                            " multipleTaskRect: " + mMultipleCountFirstTaskRect);
+                }
 
                 // If we had the update the animation rects as a result of onServiceConnected, then
                 // we check for whether we need to toggle the recents here.
@@ -83,9 +85,11 @@
     class RecentsServiceConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
-            Console.log(Constants.Log.App.RecentsComponent,
-                    "[RecentsComponent|ServiceConnection|onServiceConnected]",
-                    "toggleRecents: " + mToggleRecentsUponServiceBound);
+            if (Console.Enabled) {
+                Console.log(Constants.Log.App.RecentsComponent,
+                        "[RecentsComponent|ServiceConnection|onServiceConnected]",
+                        "toggleRecents: " + mToggleRecentsUponServiceBound);
+            }
             mService = new Messenger(service);
             mServiceIsBound = true;
 
@@ -103,8 +107,10 @@
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
-            Console.log(Constants.Log.App.RecentsComponent,
-                    "[RecentsComponent|ServiceConnection|onServiceDisconnected]");
+            if (Console.Enabled) {
+                Console.log(Constants.Log.App.RecentsComponent,
+                        "[RecentsComponent|ServiceConnection|onServiceDisconnected]");
+            }
             mService = null;
             mServiceIsBound = false;
         }
@@ -159,7 +165,9 @@
     }
 
     public void onStart() {
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
+        }
 
         // Try to create a long-running connection to the recents service
         bindToRecentsService(false);
@@ -167,7 +175,9 @@
 
     /** Shows the recents */
     public void onShowRecents(boolean triggeredFromAltTab, View statusBarView) {
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|showRecents]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|showRecents]");
+        }
         mStatusBarView = statusBarView;
         mTriggeredFromAltTab = triggeredFromAltTab;
         if (!mServiceIsBound) {
@@ -186,7 +196,9 @@
 
     /** Hides the recents */
     public void onHideRecents(boolean triggeredFromAltTab) {
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
+        }
         if (mServiceIsBound) {
             // Notify recents to close it
             try {
@@ -202,12 +214,14 @@
 
     /** Toggles the alternate recents activity */
     public void onToggleRecents(View statusBarView) {
-        Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey);
-        Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
-                Constants.Log.App.TimeRecentsLaunchKey);
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
-                "serviceIsBound: " + mServiceIsBound);
+        if (Console.Enabled) {
+            Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey);
+            Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+                    Constants.Log.App.TimeRecentsLaunchKey);
+            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+                    "serviceIsBound: " + mServiceIsBound);
+        }
         mStatusBarView = statusBarView;
         mTriggeredFromAltTab = false;
         if (!mServiceIsBound) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Console.java b/packages/SystemUI/src/com/android/systemui/recents/Console.java
index c8d97cc..33e05dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Console.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Console.java
@@ -42,6 +42,9 @@
     public static final String AnsiCyan = "\u001B[36m";     // ClickEvents
     public static final String AnsiWhite = "\u001B[37m";
 
+    // Console enabled state
+    public static final boolean Enabled = false;
+
     /** Logs a key */
     public static void log(String key) {
         log(true, key, "", AnsiReset);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 79545b3..fcbd0f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -31,8 +31,6 @@
             public static final boolean EnableTaskStackClipping = false;
             // Enables the use of theme colors as the task bar background
             public static final boolean EnableTaskBarThemeColors = true;
-            // Enables the info pane on long-pressing the task
-            public static final boolean EnableInfoPane = false;
             // Enables app-info pane on long-pressing the icon
             public static final boolean EnableDevAppInfoOnLongPress = true;
             // Enables the search bar layout
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index bae8a99..e7119f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -80,8 +80,10 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            Console.log(Constants.Log.App.SystemUIHandshake,
-                    "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
+            if (Console.Enabled) {
+                Console.log(Constants.Log.App.SystemUIHandshake,
+                        "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
+            }
             if (action.equals(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY)) {
                 if (intent.getBooleanExtra(RecentsService.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
                     // Dismiss recents, launching the focused task
@@ -164,10 +166,12 @@
                     ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
                     appWidgetId = -1;
                 }
-                Console.log(Constants.Log.App.SystemUIHandshake,
-                        "[RecentsActivity|onCreate|settings|appWidgetId]",
-                        "Id: " + appWidgetId,
-                        Console.AnsiBlue);
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.SystemUIHandshake,
+                            "[RecentsActivity|onCreate|settings|appWidgetId]",
+                            "Id: " + appWidgetId,
+                            Console.AnsiBlue);
+                }
             }
 
             // If there is no id, then bind a new search app widget
@@ -175,10 +179,12 @@
                 Pair<Integer, AppWidgetProviderInfo> widgetInfo =
                         ssp.bindSearchAppWidget(mAppWidgetHost);
                 if (widgetInfo != null) {
-                    Console.log(Constants.Log.App.SystemUIHandshake,
-                            "[RecentsActivity|onCreate|searchWidget]",
-                            "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
-                            Console.AnsiBlue);
+                    if (Console.Enabled) {
+                        Console.log(Constants.Log.App.SystemUIHandshake,
+                                "[RecentsActivity|onCreate|searchWidget]",
+                                "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
+                                Console.AnsiBlue);
+                    }
 
                     // Save the app widget id into the settings
                     config.updateSearchBarAppWidgetId(this, widgetInfo.first);
@@ -194,10 +200,12 @@
             RecentsConfiguration config = RecentsConfiguration.getInstance();
             int appWidgetId = config.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
-                Console.log(Constants.Log.App.SystemUIHandshake,
-                "[RecentsActivity|onCreate|addSearchAppWidgetView]",
-                        "Id: " + appWidgetId,
-                        Console.AnsiBlue);
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.SystemUIHandshake,
+                            "[RecentsActivity|onCreate|addSearchAppWidgetView]",
+                            "Id: " + appWidgetId,
+                            Console.AnsiBlue);
+                }
                 mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
                         mSearchAppWidgetInfo);
                 Bundle opts = new Bundle();
@@ -230,11 +238,13 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Console.logDivider(Constants.Log.App.SystemUIHandshake);
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
-                getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey, "onCreate");
+        if (Console.Enabled) {
+            Console.logDivider(Constants.Log.App.SystemUIHandshake);
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
+                    getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "onCreate");
+        }
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -277,11 +287,13 @@
         // Reset the task launched flag if we encounter an onNewIntent() before onStop()
         mTaskLaunched = false;
 
-        Console.logDivider(Constants.Log.App.SystemUIHandshake);
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
-                intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
+        if (Console.Enabled) {
+            Console.logDivider(Constants.Log.App.SystemUIHandshake);
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
+                    intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
+        }
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -296,8 +308,10 @@
 
     @Override
     protected void onStart() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
+                    Console.AnsiRed);
+        }
         super.onStart();
         mAppWidgetHost.startListening();
         mVisible = true;
@@ -305,16 +319,20 @@
 
     @Override
     protected void onResume() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
+                    Console.AnsiRed);
+        }
         super.onResume();
     }
 
     @Override
     public void onAttachedToWindow() {
-        Console.log(Constants.Log.App.SystemUIHandshake,
-                "[RecentsActivity|onAttachedToWindow]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake,
+                    "[RecentsActivity|onAttachedToWindow]", "",
+                    Console.AnsiRed);
+        }
         super.onAttachedToWindow();
 
         // Register the broadcast receiver to handle messages from our service
@@ -334,9 +352,11 @@
 
     @Override
     public void onDetachedFromWindow() {
-        Console.log(Constants.Log.App.SystemUIHandshake,
-                "[RecentsActivity|onDetachedFromWindow]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake,
+                    "[RecentsActivity|onDetachedFromWindow]", "",
+                    Console.AnsiRed);
+        }
         super.onDetachedFromWindow();
 
         // Unregister any broadcast receivers we have registered
@@ -347,15 +367,19 @@
 
     @Override
     protected void onPause() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
+                    Console.AnsiRed);
+        }
         super.onPause();
     }
 
     @Override
     protected void onStop() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
+                    Console.AnsiRed);
+        }
         super.onStop();
 
         mAppWidgetHost.stopListening();
@@ -365,8 +389,10 @@
 
     @Override
     protected void onDestroy() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
-                Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
+                    Console.AnsiRed);
+        }
         super.onDestroy();
     }
 
@@ -394,16 +420,9 @@
     public void onBackPressed() {
         boolean interceptedByInfoPanelClose = false;
 
-        // Try and return from any open info panes
-        if (Constants.DebugFlags.App.EnableInfoPane) {
-            interceptedByInfoPanelClose = mRecentsView.closeOpenInfoPanes();
-        }
-
-        // If we haven't been intercepted already, then unfilter any stacks
-        if (!interceptedByInfoPanelClose) {
-            if (!mRecentsView.unfilterFilteredStacks()) {
-                super.onBackPressed();
-            }
+        // Unfilter any stacks
+        if (!mRecentsView.unfilterFilteredStacks()) {
+            super.onBackPressed();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 8399551..d899c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -95,9 +95,11 @@
                 Configuration.ORIENTATION_LANDSCAPE;
         transposeSearchLayoutWithOrientation =
                 res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
-        Console.log(Constants.Log.UI.MeasureAndLayout,
-                "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
-                Console.AnsiGreen);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout,
+                    "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
+                    Console.AnsiGreen);
+        }
 
         displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
         animationPxMovementPerSecond =
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 1c04cb1..4bdbb20 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -45,8 +45,10 @@
 
     @Override
     public void handleMessage(Message msg) {
-        Console.log(Constants.Log.App.SystemUIHandshake,
-                "[RecentsService|handleMessage]", msg);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake,
+                    "[RecentsService|handleMessage]", msg);
+        }
 
         Context context = mContext.get();
         if (context == null) return;
@@ -139,31 +141,41 @@
 
     @Override
     public void onCreate() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
+        }
         super.onCreate();
     }
 
     @Override
     public IBinder onBind(Intent intent) {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
+        }
         return mSystemUIMessenger.getBinder();
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+        }
         return super.onUnbind(intent);
     }
 
     @Override
     public void onRebind(Intent intent) {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
+        }
         super.onRebind(intent);
     }
 
     @Override
     public void onDestroy() {
-        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+        }
         super.onDestroy();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 1c12ac2..4685186 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -50,7 +50,9 @@
 
     /** Adds a new task to the load queue */
     void addTask(Task t, boolean forceLoad) {
-        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
+        }
         if (!mQueue.contains(t)) {
             mQueue.add(t);
         }
@@ -67,7 +69,9 @@
      * force reloaded.
      */
     Pair<Task, Boolean> nextTask() {
-        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
+        }
         Task task = mQueue.poll();
         Boolean forceLoadTask = null;
         if (task != null) {
@@ -81,14 +85,18 @@
 
     /** Removes a task from the load queue */
     void removeTask(Task t) {
-        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
+        }
         mQueue.remove(t);
         mForceLoadSet.remove(t.key);
     }
 
     /** Clears all the tasks from the load queue */
     void clearTasks() {
-        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
+        }
         mQueue.clear();
         mForceLoadSet.clear();
     }
@@ -131,7 +139,9 @@
 
     /** Restarts the loader thread */
     void start(Context context) {
-        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
+        }
         mContext = context;
         mCancelled = false;
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -143,7 +153,9 @@
 
     /** Requests the loader thread to stop after the current iteration */
     void stop() {
-        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+        }
         // Mark as cancelled for the thread to pick up
         mCancelled = true;
         mSystemServicesProxy = null;
@@ -157,19 +169,25 @@
     @Override
     public void run() {
         while (true) {
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
-            if (mCancelled) {
+            if (Console.Enabled) {
                 Console.log(Constants.Log.App.TaskDataLoader,
-                        "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
+                        "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
+            }
+            if (mCancelled) {
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.TaskDataLoader,
+                            "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
+                }
                 // We have to unset the context here, since the background thread may be using it
                 // when we call stop()
                 mContext = null;
                 // If we are cancelled, then wait until we are started again
                 synchronized(mLoadThread) {
                     try {
-                        Console.log(Constants.Log.App.TaskDataLoader,
-                                "[TaskResourceLoader|waitOnLoadThreadCancelled]");
+                        if (Console.Enabled) {
+                            Console.log(Constants.Log.App.TaskDataLoader,
+                                    "[TaskResourceLoader|waitOnLoadThreadCancelled]");
+                        }
                         mLoadThread.wait();
                     } catch (InterruptedException ie) {
                         ie.printStackTrace();
@@ -185,10 +203,12 @@
                 if (t != null) {
                     Drawable loadIcon = mApplicationIconCache.get(t.key);
                     Bitmap loadThumbnail = mThumbnailCache.get(t.key);
-                    Console.log(Constants.Log.App.TaskDataLoader,
-                            "  [TaskResourceLoader|load]",
-                            t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
-                                    " forceLoad: " + forceLoadTask);
+                    if (Console.Enabled) {
+                        Console.log(Constants.Log.App.TaskDataLoader,
+                                "  [TaskResourceLoader|load]",
+                                t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
+                                        " forceLoad: " + forceLoadTask);
+                    }
                     // Load the application icon
                     if (loadIcon == null || forceLoadTask) {
                         ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
@@ -196,9 +216,10 @@
                         Drawable icon = ssp.getActivityIcon(info, t.userId);
                         if (!mCancelled) {
                             if (icon != null) {
-                                Console.log(Constants.Log.App.TaskDataLoader,
-                                        "    [TaskResourceLoader|loadIcon]",
-                                        icon);
+                                if (Console.Enabled) {
+                                    Console.log(Constants.Log.App.TaskDataLoader,
+                                            "    [TaskResourceLoader|loadIcon]", icon);
+                                }
                                 loadIcon = icon;
                                 mApplicationIconCache.put(t.key, icon);
                             }
@@ -209,9 +230,10 @@
                         Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
                         if (!mCancelled) {
                             if (thumbnail != null) {
-                                Console.log(Constants.Log.App.TaskDataLoader,
-                                        "    [TaskResourceLoader|loadThumbnail]",
-                                        thumbnail);
+                                if (Console.Enabled) {
+                                    Console.log(Constants.Log.App.TaskDataLoader,
+                                            "    [TaskResourceLoader|loadThumbnail]", thumbnail);
+                                }
                                 thumbnail.setHasAlpha(false);
                                 loadThumbnail = thumbnail;
                                 mThumbnailCache.put(t.key, thumbnail);
@@ -239,8 +261,10 @@
                 if (!mCancelled && mLoadQueue.isEmpty()) {
                     synchronized(mLoadQueue) {
                         try {
-                            Console.log(Constants.Log.App.TaskDataLoader,
-                                    "[TaskResourceLoader|waitOnLoadQueue]");
+                            if (Console.Enabled) {
+                                Console.log(Constants.Log.App.TaskDataLoader,
+                                        "[TaskResourceLoader|waitOnLoadQueue]");
+                            }
                             mWaitingOnLoadQueue = true;
                             mLoadQueue.wait();
                             mWaitingOnLoadQueue = false;
@@ -320,9 +344,11 @@
         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxThumbnailCacheSize;
 
-        Console.log(Constants.Log.App.TaskDataLoader,
-                "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
-                " iconCache: " + iconCacheSize);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader,
+                    "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
+                    " iconCache: " + iconCacheSize);
+        }
 
         // Initialize the proxy, cache and loaders
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -338,9 +364,11 @@
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         mDefaultThumbnail.eraseColor(0x00000000);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
-        Console.log(Constants.Log.App.TaskDataLoader,
-                "[RecentsTaskLoader|defaultBitmaps]",
-                "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader,
+                    "[RecentsTaskLoader|defaultBitmaps]",
+                    "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+        }
     }
 
     /** Initializes the recents task loader */
@@ -368,11 +396,13 @@
         List<ActivityManager.RecentTaskInfo> tasks =
                 ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
-        Console.log(Constants.Log.App.TimeSystemCalls,
-                "[RecentsTaskLoader|getRecentTasks]",
-                "" + (System.currentTimeMillis() - t1) + "ms");
-        Console.log(Constants.Log.App.TaskDataLoader,
-                "[RecentsTaskLoader|tasks]", "" + tasks.size());
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TimeSystemCalls,
+                    "[RecentsTaskLoader|getRecentTasks]",
+                    "" + (System.currentTimeMillis() - t1) + "ms");
+            Console.log(Constants.Log.App.TaskDataLoader,
+                    "[RecentsTaskLoader|tasks]", "" + tasks.size());
+        }
 
         return tasks;
     }
@@ -381,7 +411,9 @@
     SpaceNode reload(Context context, int preloadCount) {
         long t1 = System.currentTimeMillis();
 
-        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+        }
         Resources res = context.getResources();
         ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
         TaskStack stack = new TaskStack(context);
@@ -419,9 +451,11 @@
 
             // Preload the specified number of apps
             if (i >= (taskCount - preloadCount)) {
-                Console.log(Constants.Log.App.TaskDataLoader,
-                        "[RecentsTaskLoader|preloadTask]",
-                        "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.TaskDataLoader,
+                            "[RecentsTaskLoader|preloadTask]",
+                            "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
+                }
 
                 // Load the icon (if possible and not the foremost task, from the cache)
                 if (!isForemostTask) {
@@ -451,8 +485,10 @@
                     }
                 }
                 if (task.thumbnail == null) {
-                    Console.log(Constants.Log.App.TaskDataLoader,
-                            "[RecentsTaskLoader|loadingTaskThumbnail]");
+                    if (Console.Enabled) {
+                        Console.log(Constants.Log.App.TaskDataLoader,
+                                "[RecentsTaskLoader|loadingTaskThumbnail]");
+                    }
                     task.thumbnail = ssp.getTaskThumbnail(task.key.id);
                     if (task.thumbnail != null) {
                         task.thumbnail.setHasAlpha(false);
@@ -464,13 +500,17 @@
             }
 
             // Add the task to the stack
-            Console.log(Constants.Log.App.TaskDataLoader,
-                "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
+            if (Console.Enabled) {
+                Console.log(Constants.Log.App.TaskDataLoader,
+                        "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
+            }
             stack.addTask(task);
         }
-        Console.log(Constants.Log.App.TimeSystemCalls,
-                "[RecentsTaskLoader|getAllTaskTopThumbnail]",
-                "" + (System.currentTimeMillis() - t1) + "ms");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TimeSystemCalls,
+                    "[RecentsTaskLoader|getAllTaskTopThumbnail]",
+                    "" + (System.currentTimeMillis() - t1) + "ms");
+        }
 
         /*
         // Get all the stacks
@@ -505,9 +545,11 @@
         Drawable applicationIcon = mApplicationIconCache.get(t.key);
         Bitmap thumbnail = mThumbnailCache.get(t.key);
 
-        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
-                t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
-                        " thumbnailCacheSize: " + mThumbnailCache.size());
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
+                    t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
+                            " thumbnailCacheSize: " + mThumbnailCache.size());
+        }
 
         boolean requiresLoad = false;
         if (applicationIcon == null) {
@@ -526,9 +568,11 @@
 
     /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
-        Console.log(Constants.Log.App.TaskDataLoader,
-                "[RecentsTaskLoader|unloadTask]", t +
-                " thumbnailCacheSize: " + mThumbnailCache.size());
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader,
+                    "[RecentsTaskLoader|unloadTask]", t +
+                    " thumbnailCacheSize: " + mThumbnailCache.size());
+        }
 
         mLoadQueue.removeTask(t);
         t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
@@ -536,8 +580,10 @@
 
     /** Completely removes the resource data from the pool. */
     public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
-        Console.log(Constants.Log.App.TaskDataLoader,
-                "[RecentsTaskLoader|deleteTask]", t);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader,
+                    "[RecentsTaskLoader|deleteTask]", t);
+        }
 
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
@@ -549,7 +595,9 @@
 
     /** Stops the task loader and clears all pending tasks */
     void stopLoader() {
-        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+        }
         mLoader.stop();
         mLoadQueue.clearTasks();
     }
@@ -570,8 +618,10 @@
      * out of memory.
      */
     void onTrimMemory(int level) {
-        Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
-                Console.trimMemoryLevelToString(level));
+        if (Console.Enabled) {
+            Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+                    Console.trimMemoryLevelToString(level));
+        }
 
         switch (level) {
             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 59d0ea6..7a3ffb8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -106,7 +106,8 @@
                 rti.description = description;
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
-                        Bitmap.createBitmap(mDummyIcon), new Random().nextInt());
+                        Bitmap.createBitmap(mDummyIcon),
+                        0xFF000000 | (0xFFFFFF & new Random().nextInt()));
                 } else {
                     rti.taskDescription = new ActivityManager.TaskDescription();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c63e688..cad9ce5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -110,16 +110,20 @@
                     TaskView tv = (TaskView) stackView.getChildAt(j);
                     Task task = tv.getTask();
                     if (tv.isFocusedTask()) {
-                        Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
-                                "Found focused Task");
+                        if (Console.Enabled) {
+                            Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+                                    "Found focused Task");
+                        }
                         onTaskLaunched(stackView, tv, stack, task);
                         return true;
                     }
                 }
             }
         }
-        Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
-                "No Tasks focused");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+                    "No Tasks focused");
+        }
         return false;
     }
 
@@ -168,9 +172,11 @@
                 mSearchBar.setVisibility(mHasTasks ? View.VISIBLE : View.GONE);
                 addView(mSearchBar);
 
-                Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
-                        "" + (mSearchBar.getVisibility() == View.VISIBLE),
-                        Console.AnsiBlue);
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
+                            "" + (mSearchBar.getVisibility() == View.VISIBLE),
+                            Console.AnsiBlue);
+                }
             }
         }
     }
@@ -185,10 +191,12 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
-        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
-                "width: " + width + " height: " + height, Console.AnsiGreen);
-        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
+                    "width: " + width + " height: " + height, Console.AnsiGreen);
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+        }
 
         // Get the search bar bounds and measure the search bar layout
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -227,10 +235,12 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
-                new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
-        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
+                    new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+        }
 
         // Get the search bar bounds so that we lay it out
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -283,15 +293,19 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
-                Console.AnsiPurple);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
+                    Console.AnsiPurple);
+        }
         super.dispatchDraw(canvas);
     }
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        Console.log(Constants.Log.UI.MeasureAndLayout,
-                "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout,
+                    "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
+        }
 
         // Update the configuration with the latest system insets and trigger a relayout
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -301,24 +315,6 @@
         return insets.consumeSystemWindowInsets(false, false, false, true);
     }
 
-    /** Closes any open info panes */
-    public boolean closeOpenInfoPanes() {
-        if (mBSP != null) {
-            // Get the first stack view
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-                if (child instanceof TaskStackView) {
-                    TaskStackView stackView = (TaskStackView) child;
-                    if (stackView.closeOpenInfoPanes()) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
     /** Unfilters any filtered stacks */
     public boolean unfilterFilteredStacks() {
         if (mBSP != null) {
@@ -346,9 +342,6 @@
             mCb.onTaskLaunching();
         }
 
-        // Close any open info panes
-        closeOpenInfoPanes();
-
         final Runnable launchRunnable = new Runnable() {
             @Override
             public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index c34300c..3ee0545 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -178,9 +178,11 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.Log.UI.TouchEvents,
-                "[SwipeHelper|interceptTouchEvent]",
-                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.TouchEvents,
+                    "[SwipeHelper|interceptTouchEvent]",
+                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        }
         final int action = ev.getAction();
 
         switch (action) {
@@ -291,9 +293,11 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.Log.UI.TouchEvents,
-                "[SwipeHelper|touchEvent]",
-                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.TouchEvents,
+                    "[SwipeHelper|touchEvent]",
+                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        }
 
         if (!mDragging) {
             if (!onInterceptTouchEvent(ev)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
deleted file mode 100644
index 7b6572b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Path;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.RippleDrawable;
-import android.util.AttributeSet;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.Utilities;
-import com.android.systemui.recents.model.Task;
-
-
-/* The task info view */
-class TaskInfoView extends FrameLayout {
-
-    Button mAppInfoButton;
-
-    // Circular clip animation
-    boolean mCircularClipEnabled;
-    Path mClipPath = new Path();
-    float mClipRadius;
-    float mMaxClipRadius;
-    Point mClipOrigin = new Point();
-    ObjectAnimator mCircularClipAnimator;
-
-    public TaskInfoView(Context context) {
-        this(context, null);
-    }
-
-    public TaskInfoView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        // Initialize the buttons on the info panel
-        mAppInfoButton = (Button) findViewById(R.id.task_view_app_info_button);
-    }
-
-    /** Updates the positions of each of the items to fit in the rect specified */
-    void updateContents(Rect visibleRect) {
-        // Offset the app info button
-        mAppInfoButton.setTranslationY(visibleRect.top +
-                (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2);
-    }
-
-    /** Sets the circular clip radius on this panel */
-    public void setCircularClipRadius(float r) {
-        mClipRadius = r;
-        invalidate();
-    }
-
-    /** Gets the circular clip radius on this panel */
-    public float getCircularClipRadius() {
-        return mClipRadius;
-    }
-
-    /** Animates the circular clip radius on the icon */
-    void animateCircularClip(Point o, float fromRadius, float toRadius,
-                             final Runnable postRunnable, boolean animateInContent) {
-        if (mCircularClipAnimator != null) {
-            mCircularClipAnimator.cancel();
-        }
-
-        // Calculate the max clip radius to each of the corners
-        int w = getMeasuredWidth() - o.x;
-        int h = getMeasuredHeight() - o.y;
-        // origin to tl, tr, br, bl
-        mMaxClipRadius = (int) Math.ceil(Math.sqrt(o.x * o.x + o.y * o.y));
-        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + o.y * o.y)));
-        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + h * h)));
-        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(o.x * o.x + h * h)));
-
-        mClipOrigin.set(o.x, o.y);
-        mClipRadius = fromRadius;
-        int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
-        mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
-        mCircularClipAnimator.setDuration(duration);
-        mCircularClipAnimator.setInterpolator(
-                RecentsConfiguration.getInstance().defaultBezierInterpolator);
-        mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mCircularClipEnabled = false;
-                if (postRunnable != null) {
-                    postRunnable.run();
-                }
-            }
-        });
-        mCircularClipAnimator.start();
-        mCircularClipEnabled = true;
-
-        if (animateInContent) {
-            animateAppInfoButtonIn(duration);
-        }
-    }
-
-    /** Cancels the circular clip animation. */
-    void cancelCircularClipAnimation() {
-        if (mCircularClipAnimator != null) {
-            mCircularClipAnimator.cancel();
-        }
-    }
-
-    void animateAppInfoButtonIn(int duration) {
-        mAppInfoButton.setScaleX(0.75f);
-        mAppInfoButton.setScaleY(0.75f);
-        mAppInfoButton.animate()
-                .scaleX(1f)
-                .scaleY(1f)
-                .setDuration(duration)
-                .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator)
-                .withLayer()
-                .start();
-    }
-
-    /** Binds the info view to the task */
-    void rebindToTask(Task t, boolean animate) {
-        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
-        if (Constants.DebugFlags.App.EnableTaskBarThemeColors && t.colorPrimary != 0) {
-            setBackgroundColor(t.colorPrimary);
-            // Workaround: The button currently doesn't support setting a custom background tint
-            // not defined in the theme.  Just lower the alpha on the button to make it blend more
-            // into the background.
-            if (mAppInfoButton.getBackground() instanceof RippleDrawable) {
-                RippleDrawable d = (RippleDrawable) mAppInfoButton.getBackground();
-                if (d != null) {
-                    d.setAlpha(96);
-                }
-            }
-        } else {
-            setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        int saveCount = 0;
-        if (mCircularClipEnabled) {
-            saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            mClipPath.reset();
-            mClipPath.addCircle(mClipOrigin.x, mClipOrigin.y, mClipRadius * mMaxClipRadius,
-                    Path.Direction.CW);
-            canvas.clipPath(mClipPath);
-        }
-        super.draw(canvas);
-        if (mCircularClipEnabled) {
-            canvas.restoreToCount(saveCount);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 37c3c35..3e418ca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -54,7 +54,7 @@
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>,
-        View.OnClickListener, View.OnLongClickListener, RecentsPackageMonitor.PackageCallbacks {
+        View.OnClickListener, RecentsPackageMonitor.PackageCallbacks {
 
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
@@ -79,7 +79,6 @@
     int mMinScroll;
     int mMaxScroll;
     int mStashedScroll;
-    int mLastInfoPaneStackScroll;
     int mFocusedTaskIndex = -1;
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
@@ -114,8 +113,10 @@
         requestSynchronizeStackViewsWithModel(0);
     }
     void requestSynchronizeStackViewsWithModel(int duration) {
-        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
+                    "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
+        }
         if (!mStackViewsDirty) {
             invalidate();
         }
@@ -222,9 +223,11 @@
 
     /** Synchronizes the views with the model */
     void synchronizeStackViewsWithModel() {
-        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                "[TaskStackView|synchronizeViewsWithModel]",
-                "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
+                    "[TaskStackView|synchronizeViewsWithModel]",
+                    "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
+        }
         if (mStackViewsDirty) {
             // XXX: Consider using TaskViewTransform pool to prevent allocations
             // XXX: Iterate children views, update transforms and remove all that are not visible
@@ -278,8 +281,10 @@
                 }
             }
 
-            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                    "  [TaskStackView|viewChildren]", "" + getChildCount());
+            if (Console.Enabled) {
+                Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
+                        "  [TaskStackView|viewChildren]", "" + getChildCount());
+            }
 
             mStackViewsAnimationDuration = 0;
             mStackViewsDirty = false;
@@ -290,17 +295,6 @@
     public void setStackScroll(int value) {
         mStackScroll = value;
         requestSynchronizeStackViewsWithModel();
-
-        // Close any open info panes if the user has scrolled away from them
-        boolean isAnimatingScroll = (mScrollAnimator != null && mScrollAnimator.isRunning());
-        if (mLastInfoPaneStackScroll > -1 && !isAnimatingScroll) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-            if (Math.abs(mStackScroll - mLastInfoPaneStackScroll) >
-                    config.taskStackScrollDismissInfoPaneDistance) {
-                // Close any open info panes
-                closeOpenInfoPanes();
-            }
-        }
     }
     /** Sets the current stack scroll without synchronizing the stack view with the model */
     public void setStackScrollRaw(int value) {
@@ -455,24 +449,11 @@
         }
     }
 
-    /** Closes any open info panes. */
-    boolean closeOpenInfoPanes() {
-        if (!Constants.DebugFlags.App.EnableInfoPane) return false;
-
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
-            if (tv.isInfoPaneVisible()) {
-                tv.hideInfoPane();
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** Focuses the task at the specified index in the stack */
     void focusTask(int taskIndex, boolean scrollToNewPosition) {
-        Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex);
+        }
         if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
             mFocusedTaskIndex = taskIndex;
 
@@ -482,7 +463,9 @@
             Runnable postScrollRunnable = null;
             if (tv != null) {
                 tv.setFocusedTask();
-                Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "Requesting focus");
+                if (Console.Enabled) {
+                    Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "Requesting focus");
+                }
             } else {
                 postScrollRunnable = new Runnable() {
                     @Override
@@ -491,8 +474,10 @@
                         TaskView tv = getChildViewForTask(t);
                         if (tv != null) {
                             tv.setFocusedTask();
-                            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]",
-                                    "Requesting focus after scroll animation");
+                            if (Console.Enabled) {
+                                Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]",
+                                        "Requesting focus after scroll animation");
+                            }
                         }
                     }
                 };
@@ -514,7 +499,10 @@
 
     /** Focuses the next task in the stack */
     void focusNextTask(boolean forward) {
-        Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusNextTask]", "" + mFocusedTaskIndex);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusNextTask]", "" +
+                    mFocusedTaskIndex);
+        }
 
         // Find the next index to focus
         int numTasks = mStack.getTaskCount();
@@ -530,9 +518,11 @@
 
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
-        Console.log(Constants.Log.UI.HwLayers,
-                "[TaskStackView|addHwLayersRefCount] refCount: " +
-                        mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.HwLayers,
+                    "[TaskStackView|addHwLayersRefCount] refCount: " +
+                            mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
+        }
         if (mHwLayersRefCount == 0) {
             // Enable hw layers on each of the children
             int childCount = getChildCount();
@@ -547,9 +537,11 @@
     /** Decrements the hw layer requirement ref count and disables the hw layers when we don't
         need them anymore. */
     void decHwLayersRefCount(String reason) {
-        Console.log(Constants.Log.UI.HwLayers,
-                "[TaskStackView|decHwLayersRefCount] refCount: " +
-                        mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.HwLayers,
+                    "[TaskStackView|decHwLayersRefCount] refCount: " +
+                            mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
+        }
         mHwLayersRefCount--;
         if (mHwLayersRefCount == 0) {
             // Disable hw layers on each of the children
@@ -589,8 +581,10 @@
 
     @Override
     public void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
-                Console.AnsiPurple);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
+                    Console.AnsiPurple);
+        }
         synchronizeStackViewsWithModel();
         super.dispatchDraw(canvas);
     }
@@ -674,9 +668,11 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
-        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
-                "width: " + width + " height: " + height +
-                " awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
+                    "width: " + width + " height: " + height +
+                            " awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
+        }
 
         // Compute our stack/task rects
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -731,8 +727,10 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
-                "" + new Rect(left, top, right, bottom), Console.AnsiGreen);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
+                    "" + new Rect(left, top, right, bottom), Console.AnsiGreen);
+        }
 
         // Debug logging
         if (Constants.Log.UI.MeasureAndLayout) {
@@ -949,9 +947,6 @@
     @Override
     public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks,
                                 Task filteredTask) {
-        // Close any open info panes
-        closeOpenInfoPanes();
-
         // Stash the scroll and filtered task for us to restore to when we unfilter
         mStashedScroll = getStackScroll();
 
@@ -976,9 +971,6 @@
 
     @Override
     public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) {
-        // Close any open info panes
-        closeOpenInfoPanes();
-
         // Calculate the current task transforms
         final ArrayList<TaskViewTransform> curTaskTransforms =
                 getStackTransforms(curTasks, getStackScroll(), null, true);
@@ -1004,7 +996,9 @@
 
     @Override
     public TaskView createView(Context context) {
-        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+        if (Console.Enabled) {
+            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+        }
         return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
     }
 
@@ -1012,8 +1006,10 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
         tv.resetViewProperties();
-        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
-                tv.getTask() + " tv: " + tv);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
+                    tv.getTask() + " tv: " + tv);
+        }
 
         // Report that this tasks's data is no longer being used
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -1028,8 +1024,10 @@
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task prepareData, boolean isNewView) {
-        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
-                "isNewView: " + isNewView);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
+                    "isNewView: " + isNewView);
+        }
 
         // Setup and attach the view to the window
         Task task = prepareData;
@@ -1051,16 +1049,15 @@
         }
 
         // Add/attach the view to the hierarchy
-        Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
-                "" + insertIndex);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
+                    "" + insertIndex);
+        }
         if (isNewView) {
             addView(tv, insertIndex);
 
             // Set the callbacks and listeners for this new view
             tv.setOnClickListener(this);
-            if (Constants.DebugFlags.App.EnableInfoPane) {
-                tv.setOnLongClickListener(this);
-            }
             tv.setCallbacks(this);
         } else {
             attachViewToParent(tv, insertIndex, tv.getLayoutParams());
@@ -1081,9 +1078,11 @@
 
     @Override
     public void onTaskIconClicked(TaskView tv) {
-        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
-                tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
-                Console.AnsiCyan);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
+                    tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
+                    Console.AnsiCyan);
+        }
         if (Constants.DebugFlags.App.EnableTaskFiltering) {
             if (mStack.hasFilteredTasks()) {
                 mStack.unfilterTasks();
@@ -1094,17 +1093,6 @@
     }
 
     @Override
-    public void onTaskInfoPanelShown(TaskView tv) {
-        // Do nothing
-    }
-
-    @Override
-    public void onTaskInfoPanelHidden(TaskView tv) {
-        // Unset the saved scroll
-        mLastInfoPaneStackScroll = -1;
-    }
-
-    @Override
     public void onTaskAppInfoClicked(TaskView tv) {
         if (mCb != null) {
             mCb.onTaskAppInfoLaunched(tv.getTask());
@@ -1126,12 +1114,9 @@
     public void onClick(View v) {
         TaskView tv = (TaskView) v;
         Task task = tv.getTask();
-        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
-                task + " cb: " + mCb);
-
-        // Close any open info panes if the user taps on another task
-        if (closeOpenInfoPanes()) {
-            return;
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
+                    task + " cb: " + mCb);
         }
 
         if (mCb != null) {
@@ -1139,42 +1124,6 @@
         }
     }
 
-    @Override
-    public boolean onLongClick(View v) {
-        if (!Constants.DebugFlags.App.EnableInfoPane) return false;
-
-        TaskView tv = (TaskView) v;
-
-        // Close any other task info panels if we launch another info pane
-        closeOpenInfoPanes();
-
-        // Scroll the task view so that it is maximally visible
-        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
-        int taskIndex = mStack.indexOfTask(tv.getTask());
-        int curScroll = getStackScroll();
-        int newScroll = (int) Math.max(mMinScroll, Math.min(mMaxScroll, taskIndex * overlapHeight));
-        TaskViewTransform transform = getStackTransform(taskIndex, curScroll);
-        Rect nonOverlapRect = new Rect(transform.rect);
-        if (taskIndex < (mStack.getTaskCount() - 1)) {
-            nonOverlapRect.bottom = nonOverlapRect.top + (int) overlapHeight;
-        }
-
-        // XXX: Use HW Layers
-        if (transform.t < 0f) {
-            animateScroll(curScroll, newScroll, null);
-        } else if (nonOverlapRect.bottom > mStackRectSansPeek.bottom) {
-            // Check if we are out of bounds, if so, just scroll it in such that the bottom of the
-            // task view is visible
-            newScroll = curScroll - (mStackRectSansPeek.bottom - nonOverlapRect.bottom);
-            animateScroll(curScroll, newScroll, null);
-        }
-        mLastInfoPaneStackScroll = newScroll;
-
-        // Show the info pane for this task view
-        tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight));
-        return true;
-    }
-
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
@@ -1278,9 +1227,11 @@
 
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.Log.UI.TouchEvents,
-                "[TaskStackViewTouchHandler|interceptTouchEvent]",
-                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.TouchEvents,
+                    "[TaskStackViewTouchHandler|interceptTouchEvent]",
+                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        }
 
         // Return early if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
@@ -1362,9 +1313,11 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.Log.UI.TouchEvents,
-                "[TaskStackViewTouchHandler|touchEvent]",
-                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.TouchEvents,
+                    "[TaskStackViewTouchHandler|touchEvent]",
+                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+        }
 
         // Short circuit if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
@@ -1465,12 +1418,14 @@
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
 
-                    Console.log(Constants.Log.UI.TouchEvents,
-                            "[TaskStackViewTouchHandler|fling]",
-                            "scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
-                                    " maxVelocity: " + mMaximumVelocity +
-                                    " overscrollRange: " + overscrollRange,
-                            Console.AnsiGreen);
+                    if (Console.Enabled) {
+                        Console.log(Constants.Log.UI.TouchEvents,
+                                "[TaskStackViewTouchHandler|fling]",
+                                "scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
+                                        " maxVelocity: " + mMaximumVelocity +
+                                        " overscrollRange: " + overscrollRange,
+                                Console.AnsiGreen);
+                    }
 
                     // Fling scroll
                     mSv.mScroller.fling(0, mSv.getStackScroll(),
@@ -1550,13 +1505,6 @@
         if (parent != null) {
             parent.requestDisallowInterceptTouchEvent(true);
         }
-        // If the info panel is currently showing on this view, then we need to dismiss it
-        if (Constants.DebugFlags.App.EnableInfoPane) {
-            TaskView tv = (TaskView) v;
-            if (tv.isInfoPaneVisible()) {
-                tv.hideInfoPane();
-            }
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 46af4c1..16a3f45 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -44,8 +44,6 @@
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         public void onTaskIconClicked(TaskView tv);
-        public void onTaskInfoPanelShown(TaskView tv);
-        public void onTaskInfoPanelHidden(TaskView tv);
         public void onTaskAppInfoClicked(TaskView tv);
         public void onTaskDismissed(TaskView tv);
 
@@ -58,14 +56,12 @@
 
     Task mTask;
     boolean mTaskDataLoaded;
-    boolean mTaskInfoPaneVisible;
     boolean mIsFocused;
     Point mLastTouchDown = new Point();
     Path mRoundedRectClipPath = new Path();
 
     TaskThumbnailView mThumbnailView;
     TaskBarView mBarView;
-    TaskInfoView mInfoView;
     TaskViewCallbacks mCb;
 
 
@@ -94,7 +90,6 @@
         // Bind the views
         mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
         mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
-        mInfoView = (TaskInfoView) findViewById(R.id.task_view_info_pane);
 
         if (mTaskDataLoaded) {
             onTaskDataLoaded(false);
@@ -280,63 +275,6 @@
         return outRect;
     }
 
-    /** Returns whether this task has an info pane visible */
-    boolean isInfoPaneVisible() {
-        return mTaskInfoPaneVisible;
-    }
-
-    /** Shows the info pane if it is not visible. */
-    void showInfoPane(Rect taskVisibleRect) {
-        if (mTaskInfoPaneVisible) return;
-
-        // Remove the bar view from the visible rect and update the info pane contents
-        taskVisibleRect.top += mBarView.getMeasuredHeight();
-        mInfoView.updateContents(taskVisibleRect);
-
-        // Show the info pane and animate it into view
-        mInfoView.setVisibility(View.VISIBLE);
-        mInfoView.animateCircularClip(mLastTouchDown, 0f, 1f, null, true);
-        mInfoView.setOnClickListener(this);
-        mTaskInfoPaneVisible = true;
-
-        // Notify any callbacks
-        if (mCb != null) {
-            mCb.onTaskInfoPanelShown(this);
-        }
-    }
-
-    /** Hides the info pane if it is visible. */
-    void hideInfoPane() {
-        if (!mTaskInfoPaneVisible) return;
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-
-        // Cancel any circular clip animation
-        mInfoView.cancelCircularClipAnimation();
-
-        // Animate the info pane out
-        mInfoView.animate()
-                .alpha(0f)
-                .setDuration(config.taskViewInfoPaneAnimDuration)
-                .setInterpolator(config.defaultBezierInterpolator)
-                .withLayer()
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        mInfoView.setVisibility(View.INVISIBLE);
-                        mInfoView.setOnClickListener(null);
-
-                        mInfoView.setAlpha(1f);
-                    }
-                })
-                .start();
-        mTaskInfoPaneVisible = false;
-
-        // Notify any callbacks
-        if (mCb != null) {
-            mCb.onTaskInfoPanelHidden(this);
-        }
-    }
-
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
         mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -354,7 +292,6 @@
         float dim = (1f - getScaleX()) / scaleRange;
         dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
         mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
-        invalidate();
     }
 
     @Override
@@ -408,11 +345,10 @@
 
     @Override
     public void onTaskDataLoaded(boolean reloadingTaskData) {
-        if (mThumbnailView != null && mBarView != null && mInfoView != null) {
+        if (mThumbnailView != null && mBarView != null) {
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask, reloadingTaskData);
             mBarView.rebindToTask(mTask, reloadingTaskData);
-            mInfoView.rebindToTask(mTask, reloadingTaskData);
             // Rebind any listeners
             mBarView.mApplicationIcon.setOnClickListener(this);
             mBarView.mDismissButton.setOnClickListener(this);
@@ -424,16 +360,13 @@
                     mBarView.mApplicationIcon.setOnLongClickListener(this);
                 }
             }
-            if (Constants.DebugFlags.App.EnableInfoPane) {
-                mInfoView.mAppInfoButton.setOnClickListener(this);
-            }
         }
         mTaskDataLoaded = true;
     }
 
     @Override
     public void onTaskDataUnloaded() {
-        if (mThumbnailView != null && mBarView != null && mInfoView != null) {
+        if (mThumbnailView != null && mBarView != null) {
             // Unbind each of the views from the task data and remove the task callback
             mTask.setCallbacks(null);
             mThumbnailView.unbindFromTask();
@@ -444,18 +377,13 @@
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 mBarView.mApplicationIcon.setOnLongClickListener(null);
             }
-            if (Constants.DebugFlags.App.EnableInfoPane) {
-                mInfoView.mAppInfoButton.setOnClickListener(null);
-            }
         }
         mTaskDataLoaded = false;
     }
 
     @Override
     public void onClick(View v) {
-        if (v == mInfoView) {
-            hideInfoPane();
-        } else if (v == mBarView.mApplicationIcon) {
+        if (v == mBarView.mApplicationIcon) {
             mCb.onTaskIconClicked(this);
         } else if (v == mBarView.mDismissButton) {
             // Animate out the view and call the callback
@@ -466,8 +394,6 @@
                     mCb.onTaskDismissed(tv);
                 }
             });
-        } else if (v == mInfoView.mAppInfoButton) {
-            mCb.onTaskAppInfoClicked(this);
         }
     }
 
@@ -479,4 +405,4 @@
         }
         return false;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 724b6a4..ac16164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -89,7 +89,7 @@
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
-        updateBackgroundResource();
+        updateBackgroundResources();
     }
 
     private final Runnable mTapTimeoutRunnable = new Runnable() {
@@ -215,9 +215,9 @@
         if (mDimmed != dimmed) {
             mDimmed = dimmed;
             if (fade) {
-                fadeBackgroundResource();
+                fadeBackground();
             } else {
-                updateBackgroundResource();
+                updateBackground();
             }
         }
     }
@@ -233,14 +233,14 @@
         mBgTint = bgTint;
         mDimmedBgResId = dimmedBgResId;
         mDimmedBgTint = dimmedTint;
-        updateBackgroundResource();
+        updateBackgroundResources();
     }
 
     public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
         setBackgroundResourceIds(bgResId, 0, dimmedBgResId, 0);
     }
 
-    private void fadeBackgroundResource() {
+    private void fadeBackground() {
         if (mDimmed) {
             mBackgroundDimmed.setVisibility(View.VISIBLE);
         } else {
@@ -256,7 +256,7 @@
             mBackgroundAnimator.removeAllListeners();
             mBackgroundAnimator.cancel();
             if (duration <= 0) {
-                updateBackgroundResource();
+                updateBackground();
                 return;
             }
         }
@@ -279,19 +279,22 @@
         mBackgroundAnimator.start();
     }
 
-    private void updateBackgroundResource() {
+    private void updateBackground() {
         if (mDimmed) {
             mBackgroundDimmed.setVisibility(View.VISIBLE);
-            mBackgroundDimmed.setCustomBackground(mDimmedBgResId, mDimmedBgTint);
             mBackgroundNormal.setVisibility(View.INVISIBLE);
         } else {
             mBackgroundDimmed.setVisibility(View.INVISIBLE);
             mBackgroundNormal.setVisibility(View.VISIBLE);
-            mBackgroundNormal.setCustomBackground(mBgResId, mBgTint);
             mBackgroundNormal.setAlpha(1f);
         }
     }
 
+    private void updateBackgroundResources() {
+        mBackgroundDimmed.setCustomBackground(mDimmedBgResId, mDimmedBgTint);
+        mBackgroundNormal.setCustomBackground(mBgResId, mBgTint);
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index eb4e77a..e699dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -619,7 +619,6 @@
 
     protected void hideRecents(boolean triggeredFromAltTab) {
         if (mRecents != null) {
-            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
             mRecents.hideRecents(triggeredFromAltTab);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f6c80fc..84005d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -53,6 +53,7 @@
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
     private boolean mIsBelowSpeedBump;
+    private View mVetoButton;
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -63,6 +64,7 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
+        mVetoButton = findViewById(R.id.veto);
     }
 
     @Override
@@ -224,7 +226,7 @@
 
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
-        mPrivateLayout.setActualHeight(height, notifyListeners);
+        mPrivateLayout.setActualHeight(height);
         invalidate();
         super.setActualHeight(height, notifyListeners);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 061396d..eaaac10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -20,29 +20,78 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
+import com.android.systemui.R;
+
+import java.util.ArrayList;
 
 /**
  * An abstract view for expandable views.
  */
 public abstract class ExpandableView extends FrameLayout {
 
+    private final int mMaxNotificationHeight;
+
     private OnHeightChangedListener mOnHeightChangedListener;
     protected int mActualHeight;
     protected int mClipTopAmount;
     private boolean mActualHeightInitialized;
+    private ArrayList<View> mMatchParentViews = new ArrayList<View>();
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mMaxNotificationHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_max_height);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int ownMaxHeight = mMaxNotificationHeight;
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
+        boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
+        if (hasFixedHeight || isHeightLimited) {
+            int size = MeasureSpec.getSize(heightMeasureSpec);
+            ownMaxHeight = Math.min(ownMaxHeight, size);
+        }
+        int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+        int maxChildHeight = 0;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            int childHeightSpec = newHeightSpec;
+            ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
+            if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
+                if (layoutParams.height >= 0) {
+                    // An actual height is set
+                    childHeightSpec = layoutParams.height > ownMaxHeight
+                        ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
+                        : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
+                }
+                child.measure(widthMeasureSpec, childHeightSpec);
+                int childHeight = child.getMeasuredHeight();
+                maxChildHeight = Math.max(maxChildHeight, childHeight);
+            } else {
+                mMatchParentViews.add(child);
+            }
+        }
+        int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight;
+        newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
+        for (View child : mMatchParentViews) {
+            child.measure(widthMeasureSpec, newHeightSpec);
+        }
+        mMatchParentViews.clear();
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        setMeasuredDimension(width, ownHeight);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mActualHeightInitialized && mActualHeight == 0) {
-            mActualHeight = getInitialHeight();
+            setActualHeight(getInitialHeight());
         }
-        mActualHeightInitialized = true;
     }
 
     protected int getInitialHeight() {
@@ -77,6 +126,7 @@
     }
 
     public void setActualHeight(int actualHeight) {
+        mActualHeightInitialized = true;
         setActualHeight(actualHeight, true);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index e49ec64..3c080fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -31,7 +31,6 @@
     private Drawable mBackground;
     private int mClipTopAmount;
     private int mActualHeight;
-    private boolean mActualHeightInitialized;
 
     public NotificationBackgroundView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -39,15 +38,6 @@
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (!mActualHeightInitialized && mActualHeight == 0) {
-            mActualHeight = getHeight();
-        }
-        mActualHeightInitialized = true;
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
         draw(canvas, mBackground);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 9df2701..f9baecb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -22,6 +22,7 @@
 import android.view.Gravity;
 import android.view.View;
 
+import android.widget.FrameLayout;
 import com.android.systemui.R;
 
 /**
@@ -29,7 +30,7 @@
  * expanded layout. This class is responsible for clipping the content and and switching between the
  * expanded and contracted view depending on its clipped size.
  */
-public class NotificationContentView extends ExpandableView {
+public class NotificationContentView extends FrameLayout {
 
     private final Rect mClipBounds = new Rect();
 
@@ -37,6 +38,8 @@
     private View mExpandedChild;
 
     private int mSmallHeight;
+    private int mClipTopAmount;
+    private int mActualHeight;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -69,28 +72,24 @@
         selectLayout();
     }
 
-    @Override
-    public void setActualHeight(int actualHeight, boolean notifyListeners) {
-        super.setActualHeight(actualHeight, notifyListeners);
+    public void setActualHeight(int actualHeight) {
+        mActualHeight = actualHeight;
         selectLayout();
         updateClipping();
     }
 
-    @Override
     public int getMaxHeight() {
 
         // The maximum height is just the laid out height.
         return getHeight();
     }
 
-    @Override
     public int getMinHeight() {
         return mSmallHeight;
     }
 
-    @Override
     public void setClipTopAmount(int clipTopAmount) {
-        super.setClipTopAmount(clipTopAmount);
+        mClipTopAmount = clipTopAmount;
         updateClipping();
     }
 
@@ -127,7 +126,6 @@
         selectLayout();
     }
 
-    @Override
     public boolean isContentExpandable() {
         return mExpandedChild != null;
     }
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 49e1072..bfbd60d 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -121,7 +121,7 @@
                 }
             } else {
                 vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
-                vis = (vis & View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
+                vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
             }
         }
         return vis;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index 5602206..a4c2ddd 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -115,13 +115,14 @@
         }
     }
 
-    public void immersiveModeChanged(String pkg, boolean isImmersiveMode) {
+    public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
+            boolean userSetupComplete) {
         mHandler.removeMessages(H.SHOW);
         if (isImmersiveMode) {
             final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
             if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
                     disabled, mConfirmed));
-            if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed)) {
+            if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) {
                 mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
             }
         } else {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6390a69..d0305e0 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -775,6 +775,11 @@
                 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
     }
 
+    boolean isUserSetupComplete() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
     private void handleLongPressOnHome() {
         if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
             mHomeConsumed = true;
@@ -4294,6 +4299,10 @@
 
     private void requestTransientBars(WindowState swipeTarget) {
         synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+            if (!isUserSetupComplete()) {
+                // Swipe-up for navigation bar is disabled during setup
+                return;
+            }
             boolean sb = mStatusBarController.checkShowTransientBarLw();
             boolean nb = mNavigationBarController.checkShowTransientBarLw();
             if (sb || nb) {
@@ -5270,7 +5279,8 @@
         boolean newImmersiveMode = isImmersiveMode(vis);
         if (win != null && oldImmersiveMode != newImmersiveMode) {
             final String pkg = win.getOwningPackage();
-            mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode);
+            mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode,
+                    isUserSetupComplete());
         }
 
         vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 168742f..4ab8a01 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -22,7 +22,6 @@
 import android.app.IAlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -40,7 +39,6 @@
 import android.os.WorkSource;
 import android.text.TextUtils;
 import android.util.ArrayMap;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -104,13 +102,21 @@
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
     boolean mLastWakeLockUnimportantForLogging;
+    ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>();
     ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
     final AlarmHandler mHandler = new AlarmHandler();
     ClockReceiver mClockReceiver;
+    InteractiveStateReceiver mInteractiveStateReceiver;
     private UninstallReceiver mUninstallReceiver;
     final ResultReceiver mResultReceiver = new ResultReceiver();
     PendingIntent mTimeTickSender;
     PendingIntent mDateChangeSender;
+    boolean mInteractive = true;
+    long mNonInteractiveStartTime;
+    long mNonInteractiveTime;
+    long mLastAlarmDeliveryTime;
+    long mStartCurrentDelayTime;
+    long mNextNonWakeupDeliveryTime;
 
     class WakeupEvent {
         public long when;
@@ -318,7 +324,11 @@
     final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
         @Override
         public int compare(Alarm lhs, Alarm rhs) {
-            if (lhs.wakeup != rhs.wakeup) {
+            if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage()))
+                    && lhs.wakeup != rhs.wakeup) {
+                // We want to put wakeup alarms before non-wakeup alarms, since they are
+                // the things that drive most activity in the alarm manager.  However,
+                // alarms from the same package should always be ordered strictly by time.
                 return lhs.wakeup ? -1 : 1;
             }
             if (lhs.whenElapsed < rhs.whenElapsed) {
@@ -424,24 +434,21 @@
     static final class InFlight extends Intent {
         final PendingIntent mPendingIntent;
         final WorkSource mWorkSource;
-        final Pair<String, ComponentName> mTarget;
+        final String mTag;
         final BroadcastStats mBroadcastStats;
         final FilterStats mFilterStats;
         final int mAlarmType;
 
         InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
-                int alarmType) {
+                int alarmType, String tag) {
             mPendingIntent = pendingIntent;
             mWorkSource = workSource;
-            Intent intent = pendingIntent.getIntent();
-            mTarget = intent != null
-                    ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
-                    : null;
+            mTag = tag;
             mBroadcastStats = service.getStatsLocked(pendingIntent);
-            FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
+            FilterStats fs = mBroadcastStats.filterStats.get(mTag);
             if (fs == null) {
-                fs = new FilterStats(mBroadcastStats, mTarget);
-                mBroadcastStats.filterStats.put(mTarget, fs);
+                fs = new FilterStats(mBroadcastStats, mTag);
+                mBroadcastStats.filterStats.put(mTag, fs);
             }
             mFilterStats = fs;
             mAlarmType = alarmType;
@@ -450,7 +457,7 @@
 
     static final class FilterStats {
         final BroadcastStats mBroadcastStats;
-        final Pair<String, ComponentName> mTarget;
+        final String mTag;
 
         long aggregateTime;
         int count;
@@ -458,9 +465,9 @@
         long startTime;
         int nesting;
 
-        FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
+        FilterStats(BroadcastStats broadcastStats, String tag) {
             mBroadcastStats = broadcastStats;
-            mTarget = target;
+            mTag = tag;
         }
     }
     
@@ -473,8 +480,7 @@
         int numWakeup;
         long startTime;
         int nesting;
-        final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats
-                = new ArrayMap<Pair<String, ComponentName>, FilterStats>();
+        final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>();
 
         BroadcastStats(int uid, String packageName) {
             mUid = uid;
@@ -484,7 +490,11 @@
     
     final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
             = new SparseArray<ArrayMap<String, BroadcastStats>>();
-    
+
+    int mNumDelayedAlarms = 0;
+    long mTotalDelayTime = 0;
+    long mMaxDelayTime = 0;
+
     @Override
     public void onStart() {
         mNativeData = init();
@@ -511,6 +521,7 @@
         mClockReceiver = new ClockReceiver();
         mClockReceiver.scheduleTimeTickEvent();
         mClockReceiver.scheduleDateChangedEvent();
+        mInteractiveStateReceiver = new InteractiveStateReceiver();
         mUninstallReceiver = new UninstallReceiver();
         
         if (mNativeData != 0) {
@@ -735,13 +746,29 @@
 
             pw.print("nowRTC="); pw.print(nowRTC);
             pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
-            pw.print(" nowELAPSED="); pw.println(nowELAPSED);
+            pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
+            pw.println();
+            if (!mInteractive) {
+                pw.print("Time since non-interactive: ");
+                TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
+                pw.println();
+                pw.print("Max wakeup delay: ");
+                TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
+                pw.println();
+                pw.print("Time since last dispatch: ");
+                TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
+                pw.println();
+                pw.print("Next non-wakeup delivery time: ");
+                TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
+                pw.println();
+            }
 
             long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
             long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
-            pw.print("Next alarm: "); pw.print(mNextNonWakeup);
+            pw.print("Next non-wakeup alarm: ");
+                    TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
-            pw.print("Next wakeup: "); pw.print(mNextWakeup);
+            pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
 
             if (mAlarmBatches.size() > 0) {
@@ -750,11 +777,27 @@
                 pw.println(mAlarmBatches.size());
                 for (Batch b : mAlarmBatches) {
                     pw.print(b); pw.println(':');
-                    dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC);
+                    dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC, sdf);
                 }
             }
 
             pw.println();
+            pw.print("Past-due non-wakeup alarms: ");
+            if (mPendingNonWakeupAlarms.size() > 0) {
+                pw.println(mPendingNonWakeupAlarms.size());
+                dumpAlarmList(pw, mPendingNonWakeupAlarms, "  ", nowELAPSED, nowRTC, sdf);
+            } else {
+                pw.println("(none)");
+            }
+            pw.print("  Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
+            pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
+            pw.println();
+            pw.print("  Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
+            pw.print(", max non-interactive time: ");
+            TimeUtils.formatDuration(mNonInteractiveTime, pw);
+            pw.println();
+
+            pw.println();
             pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
             pw.println();
 
@@ -811,13 +854,7 @@
                     pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
                     pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
                     pw.println();
-                    pw.print("      ");
-                    if (fs.mTarget.first != null) {
-                        pw.print(" act="); pw.print(fs.mTarget.first);
-                    }
-                    if (fs.mTarget.second != null) {
-                        pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
-                    }
+                    pw.print("      "); pw.print(fs.mTag);
                     pw.println();
                 }
             }
@@ -849,13 +886,8 @@
                                 TimeUtils.formatDuration(fs.aggregateTime, pw);
                                 pw.print(" "); pw.print(fs.numWakeup);
                                 pw.print(" wakes " ); pw.print(fs.count);
-                                pw.print(" alarms:");
-                                if (fs.mTarget.first != null) {
-                                    pw.print(" act="); pw.print(fs.mTarget.first);
-                                }
-                                if (fs.mTarget.second != null) {
-                                    pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
-                                }
+                                pw.print(" alarms: ");
+                                pw.print(fs.mTag);
                                 pw.println();
                     }
                 }
@@ -883,7 +915,7 @@
         }
     }
 
-    private void logBatchesLocked() {
+    private void logBatchesLocked(SimpleDateFormat sdf) {
         ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
         PrintWriter pw = new PrintWriter(bs);
         final long nowRTC = System.currentTimeMillis();
@@ -892,7 +924,7 @@
         for (int iz = 0; iz < NZ; iz++) {
             Batch bz = mAlarmBatches.get(iz);
             pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
-            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
+            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC, sdf);
             pw.flush();
             Slog.v(TAG, bs.toString());
             bs.reset();
@@ -910,7 +942,8 @@
                     lastTime = b.start;
                 } else {
                     Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
-                    logBatchesLocked();
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    logBatchesLocked(sdf);
                     return false;
                 }
             }
@@ -932,6 +965,7 @@
     void rescheduleKernelAlarmsLocked() {
         // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
         // prior to that which contains no wakeups, we schedule that as well.
+        long nextNonWakeup = 0;
         if (mAlarmBatches.size() > 0) {
             final Batch firstWakeup = findFirstWakeupBatchLocked();
             final Batch firstBatch = mAlarmBatches.get(0);
@@ -939,11 +973,19 @@
                 mNextWakeup = firstWakeup.start;
                 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
             }
-            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
-                mNextNonWakeup = firstBatch.start;
-                setLocked(ELAPSED_REALTIME, firstBatch.start);
+            if (firstBatch != firstWakeup) {
+                nextNonWakeup = firstBatch.start;
             }
         }
+        if (mPendingNonWakeupAlarms.size() > 0) {
+            if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
+                nextNonWakeup = mNextNonWakeupDeliveryTime;
+            }
+        }
+        if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
+            mNextNonWakeup = nextNonWakeup;
+            setLocked(ELAPSED_REALTIME, nextNonWakeup);
+        }
     }
 
     private void removeLocked(PendingIntent operation) {
@@ -1003,6 +1045,32 @@
         }
     }
 
+    void interactiveStateChangedLocked(boolean interactive) {
+        if (mInteractive != interactive) {
+            mInteractive = interactive;
+            final long nowELAPSED = SystemClock.elapsedRealtime();
+            if (interactive) {
+                if (mPendingNonWakeupAlarms.size() > 0) {
+                    final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
+                    mTotalDelayTime += thisDelayTime;
+                    if (mMaxDelayTime < thisDelayTime) {
+                        mMaxDelayTime = thisDelayTime;
+                    }
+                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
+                    mPendingNonWakeupAlarms.clear();
+                }
+                if (mNonInteractiveStartTime > 0) {
+                    long dur = nowELAPSED - mNonInteractiveStartTime;
+                    if (dur > mNonInteractiveTime) {
+                        mNonInteractiveTime = dur;
+                    }
+                }
+            } else {
+                mNonInteractiveStartTime = nowELAPSED;
+            }
+        }
+    }
+
     boolean lookForPackageLocked(String packageName) {
         for (int i = 0; i < mAlarmBatches.size(); i++) {
             Batch b = mAlarmBatches.get(i);
@@ -1037,12 +1105,12 @@
     }
 
     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
-            String prefix, String label, long now) {
+            String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
         for (int i=list.size()-1; i>=0; i--) {
             Alarm a = list.get(i);
             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
                     pw.print(": "); pw.println(a);
-            a.dump(pw, prefix + "  ", now);
+            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
         }
     }
 
@@ -1059,14 +1127,13 @@
     }
 
     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
-            String prefix, long nowELAPSED, long nowRTC) {
+            String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
         for (int i=list.size()-1; i>=0; i--) {
             Alarm a = list.get(i);
             final String label = labelForType(a.type);
-            long now = (a.type <= RTC) ? nowRTC : nowELAPSED;
             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
                     pw.print(": "); pw.println(a);
-            a.dump(pw, prefix + "  ", now);
+            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
         }
     }
 
@@ -1077,8 +1144,9 @@
     private native int setKernelTime(long nativeData, long millis);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
+    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
             final long nowRTC) {
+        boolean hasWakeup = false;
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1113,8 +1181,14 @@
                             maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
                             alarm.repeatInterval, alarm.operation, batch.standalone, true,
                             alarm.workSource);
-                }
 
+                    // For now we count this as a wakeup alarm, meaning it needs to be
+                    // delivered immediately.  In the future we should change this, but
+                    // that required delaying when we reschedule the repeat...!
+                    hasWakeup = false;
+                } else if (alarm.wakeup) {
+                    hasWakeup = true;
+                }
             }
         }
 
@@ -1125,6 +1199,8 @@
                 Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
             }
         }
+
+        return hasWakeup;
     }
 
     /**
@@ -1147,15 +1223,16 @@
     private static class Alarm {
         public final int type;
         public final boolean wakeup;
+        public final PendingIntent operation;
+        public final String  tag;
+        public final WorkSource workSource;
         public int count;
         public long when;
         public long windowLength;
         public long whenElapsed;    // 'when' in the elapsed time base
         public long maxWhen;        // also in the elapsed time base
         public long repeatInterval;
-        public PendingIntent operation;
-        public WorkSource workSource;
-        
+
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws) {
             type = _type;
@@ -1167,12 +1244,17 @@
             maxWhen = _maxWhen;
             repeatInterval = _interval;
             operation = _op;
+            tag = makeTag(_op, _type);
             workSource = _ws;
         }
 
+        public static String makeTag(PendingIntent pi, int type) {
+            return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
+                    ? "*walarm*:" : "*alarm*:");
+        }
+
         @Override
-        public String toString()
-        {
+        public String toString() {
             StringBuilder sb = new StringBuilder(128);
             sb.append("Alarm{");
             sb.append(Integer.toHexString(System.identityHashCode(this)));
@@ -1186,11 +1268,20 @@
             return sb.toString();
         }
 
-        public void dump(PrintWriter pw, String prefix, long now) {
+        public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
+                SimpleDateFormat sdf) {
+            final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
+            pw.print(prefix); pw.print("tag="); pw.println(tag);
             pw.print(prefix); pw.print("type="); pw.print(type);
-                    pw.print(" whenElapsed="); pw.print(whenElapsed);
-                    pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
-                    pw.print(" window="); pw.print(windowLength);
+                    pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
+                            nowELAPSED, pw);
+                    if (isRtc) {
+                        pw.print(" when="); pw.print(sdf.format(new Date(when)));
+                    } else {
+                        pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
+                    }
+                    pw.println();
+            pw.print(prefix); pw.print("window="); pw.print(windowLength);
                     pw.print(" repeatInterval="); pw.print(repeatInterval);
                     pw.print(" count="); pw.println(count);
             pw.print(prefix); pw.print("operation="); pw.println(operation);
@@ -1216,6 +1307,102 @@
         }
     }
 
+    long currentNonWakeupFuzzLocked(long nowELAPSED) {
+        long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
+        if (timeSinceOn < 5*60*1000) {
+            // If the screen has been off for 5 minutes, only delay by at most two minutes.
+            return 2*60*1000;
+        } else if (timeSinceOn < 30*60*1000) {
+            // If the screen has been off for 30 minutes, only delay by at most 15 minutes.
+            return 15*60*1000;
+        } else {
+            // Otherwise, we will delay by at most an hour.
+            return 60*60*1000;
+        }
+    }
+
+    boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
+        if (mInteractive) {
+            return false;
+        }
+        if (mLastAlarmDeliveryTime <= 0) {
+            return false;
+        }
+        if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {
+            // This is just a little paranoia, if somehow we have pending non-wakeup alarms
+            // and the next delivery time is in the past, then just deliver them all.  This
+            // avoids bugs where we get stuck in a loop trying to poll for alarms.
+            return false;
+        }
+        long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
+        return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
+    }
+
+    void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
+        mLastAlarmDeliveryTime = nowELAPSED;
+        for (int i=0; i<triggerList.size(); i++) {
+            Alarm alarm = triggerList.get(i);
+            try {
+                if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
+                alarm.operation.send(getContext(), 0,
+                        mBackgroundIntent.putExtra(
+                                Intent.EXTRA_ALARM_COUNT, alarm.count),
+                        mResultReceiver, mHandler);
+
+                // we have an active broadcast so stay awake.
+                if (mBroadcastRefCount == 0) {
+                    setWakelockWorkSource(alarm.operation, alarm.workSource,
+                            alarm.type, alarm.tag, true);
+                    mWakeLock.acquire();
+                }
+                final InFlight inflight = new InFlight(AlarmManagerService.this,
+                        alarm.operation, alarm.workSource, alarm.type, alarm.tag);
+                mInFlight.add(inflight);
+                mBroadcastRefCount++;
+
+                final BroadcastStats bs = inflight.mBroadcastStats;
+                bs.count++;
+                if (bs.nesting == 0) {
+                    bs.nesting = 1;
+                    bs.startTime = nowELAPSED;
+                } else {
+                    bs.nesting++;
+                }
+                final FilterStats fs = inflight.mFilterStats;
+                fs.count++;
+                if (fs.nesting == 0) {
+                    fs.nesting = 1;
+                    fs.startTime = nowELAPSED;
+                } else {
+                    fs.nesting++;
+                }
+                if (alarm.type == ELAPSED_REALTIME_WAKEUP
+                        || alarm.type == RTC_WAKEUP) {
+                    bs.numWakeup++;
+                    fs.numWakeup++;
+                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
+                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
+                            ActivityManagerNative.noteWakeupAlarm(
+                                    alarm.operation, alarm.workSource.get(wi),
+                                    alarm.workSource.getName(wi));
+                        }
+                    } else {
+                        ActivityManagerNative.noteWakeupAlarm(
+                                alarm.operation, -1, null);
+                    }
+                }
+            } catch (PendingIntent.CanceledException e) {
+                if (alarm.repeatInterval > 0) {
+                    // This IntentSender is no longer valid, but this
+                    // is a repeating alarm, so toss the hoser.
+                    removeImpl(alarm.operation);
+                }
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Failure sending alarm.", e);
+            }
+        }
+    }
+
     private class AlarmThread extends Thread
     {
         public AlarmThread()
@@ -1269,70 +1456,35 @@
                         }
                     }
 
-                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
-                    rescheduleKernelAlarmsLocked();
-
-                    // now deliver the alarm intents
-                    for (int i=0; i<triggerList.size(); i++) {
-                        Alarm alarm = triggerList.get(i);
-                        try {
-                            if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
-                            alarm.operation.send(getContext(), 0,
-                                    mBackgroundIntent.putExtra(
-                                            Intent.EXTRA_ALARM_COUNT, alarm.count),
-                                    mResultReceiver, mHandler);
-                            
-                            // we have an active broadcast so stay awake.
-                            if (mBroadcastRefCount == 0) {
-                                setWakelockWorkSource(alarm.operation, alarm.workSource,
-                                        alarm.type, true);
-                                mWakeLock.acquire();
-                            }
-                            final InFlight inflight = new InFlight(AlarmManagerService.this,
-                                    alarm.operation, alarm.workSource, alarm.type);
-                            mInFlight.add(inflight);
-                            mBroadcastRefCount++;
-
-                            final BroadcastStats bs = inflight.mBroadcastStats;
-                            bs.count++;
-                            if (bs.nesting == 0) {
-                                bs.nesting = 1;
-                                bs.startTime = nowELAPSED;
-                            } else {
-                                bs.nesting++;
-                            }
-                            final FilterStats fs = inflight.mFilterStats;
-                            fs.count++;
-                            if (fs.nesting == 0) {
-                                fs.nesting = 1;
-                                fs.startTime = nowELAPSED;
-                            } else {
-                                fs.nesting++;
-                            }
-                            if (alarm.type == ELAPSED_REALTIME_WAKEUP
-                                    || alarm.type == RTC_WAKEUP) {
-                                bs.numWakeup++;
-                                fs.numWakeup++;
-                                if (alarm.workSource != null && alarm.workSource.size() > 0) {
-                                    for (int wi=0; wi<alarm.workSource.size(); wi++) {
-                                        ActivityManagerNative.noteWakeupAlarm(
-                                                alarm.operation, alarm.workSource.get(wi),
-                                                alarm.workSource.getName(wi));
-                                    }
-                                } else {
-                                    ActivityManagerNative.noteWakeupAlarm(
-                                            alarm.operation, -1, null);
-                                }
-                            }
-                        } catch (PendingIntent.CanceledException e) {
-                            if (alarm.repeatInterval > 0) {
-                                // This IntentSender is no longer valid, but this
-                                // is a repeating alarm, so toss the hoser.
-                                removeImpl(alarm.operation);
-                            }
-                        } catch (RuntimeException e) {
-                            Slog.w(TAG, "Failure sending alarm.", e);
+                    boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                    if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
+                        // if there are no wakeup alarms and the screen is off, we can
+                        // delay what we have so far until the future.
+                        if (mPendingNonWakeupAlarms.size() == 0) {
+                            mStartCurrentDelayTime = nowELAPSED;
+                            mNextNonWakeupDeliveryTime = nowELAPSED
+                                    + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
                         }
+                        mPendingNonWakeupAlarms.addAll(triggerList);
+                        mNumDelayedAlarms += triggerList.size();
+                        rescheduleKernelAlarmsLocked();
+                    } else {
+                        // now deliver the alarm intents; if there are pending non-wakeup
+                        // alarms, we need to merge them in to the list.  note we don't
+                        // just deliver them first because we generally want non-wakeup
+                        // alarms delivered after wakeup alarms.
+                        rescheduleKernelAlarmsLocked();
+                        if (mPendingNonWakeupAlarms.size() > 0) {
+                            triggerList.addAll(mPendingNonWakeupAlarms);
+                            Collections.sort(triggerList, mAlarmDispatchComparator);
+                            final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
+                            mTotalDelayTime += thisDelayTime;
+                            if (mMaxDelayTime < thisDelayTime) {
+                                mMaxDelayTime = thisDelayTime;
+                            }
+                            mPendingNonWakeupAlarms.clear();
+                        }
+                        deliverAlarmsLocked(triggerList, nowELAPSED);
                     }
                 }
             }
@@ -1344,14 +1496,13 @@
      * @param pi PendingIntent to attribute blame to if ws is null.
      * @param ws WorkSource to attribute blame.
      */
-    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) {
+    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
+            boolean first) {
         try {
             final boolean unimportant = pi == mTimeTickSender;
             mWakeLock.setUnimportantForLogging(unimportant);
             if (first || mLastWakeLockUnimportantForLogging) {
-                mWakeLock.setHistoryTag(pi.getTag(
-                        type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
-                                ? "*walarm*:" : "*alarm*:"));
+                mWakeLock.setHistoryTag(tag);
             } else {
                 mWakeLock.setHistoryTag(null);
             }
@@ -1462,6 +1613,23 @@
         }
     }
     
+    class InteractiveStateReceiver extends BroadcastReceiver {
+        public InteractiveStateReceiver() {
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+            getContext().registerReceiver(this, filter);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mLock) {
+                interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
+            }
+        }
+    }
+
     class UninstallReceiver extends BroadcastReceiver {
         public UninstallReceiver() {
             IntentFilter filter = new IntentFilter();
@@ -1589,7 +1757,7 @@
                     if (mInFlight.size() > 0) {
                         InFlight inFlight = mInFlight.get(0);
                         setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
-                                inFlight.mAlarmType, false);
+                                inFlight.mAlarmType, inFlight.mTag, false);
                     } else {
                         // should never happen
                         mLog.w("Alarm wakelock still held but sent queue empty");
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index be20616..bfa0402 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1253,7 +1253,10 @@
     public void removeUser(int userHandle) throws RemoteException {
         checkSystemUid("removeUser");
         mOpRestrictions.remove(userHandle);
-        mProfileOwnerUids.removeAt(mProfileOwnerUids.indexOfKey(userHandle));
+        final int index = mProfileOwnerUids.indexOfKey(userHandle);
+        if (index >= 0) {
+            mProfileOwnerUids.removeAt(index);
+        }
     }
 
     private void checkSystemUid(String function) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index cc132be..af53fef0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -398,7 +398,7 @@
 
     /**
      * used internally when registering NetworkFactories
-     * obj = Messenger
+     * obj = NetworkFactoryInfo
      */
     private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
 
@@ -434,6 +434,13 @@
      */
     private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
 
+    /**
+     * used internally when registering NetworkFactories
+     * obj = Messenger
+     */
+    private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23;
+
+
     /** Handler used for internal events. */
     final private InternalHandler mHandler;
     /** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -2889,6 +2896,14 @@
             return;
         }
 
+        pw.println("NetworkFactories for:");
+        pw.increaseIndent();
+        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
+            pw.println(nfi.name);
+        }
+        pw.decreaseIndent();
+        pw.println();
+
         NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
         pw.print("Active default network: ");
         if (defaultNai == null) {
@@ -2983,6 +2998,7 @@
                     if (nai == null) {
                         loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
                     } else {
+                        if (VDBG) log("Update of Linkproperties for " + nai.name());
                         LinkProperties oldLp = nai.linkProperties;
                         nai.linkProperties = (LinkProperties)msg.obj;
                         updateLinkProperties(nai, oldLp);
@@ -3096,18 +3112,19 @@
 
     private void handleAsyncChannelHalfConnect(Message msg) {
         AsyncChannel ac = (AsyncChannel) msg.obj;
-        if (mNetworkFactories.contains(ac)) {
+        if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
             if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                 if (VDBG) log("NetworkFactory connected");
                 // A network factory has connected.  Send it all current NetworkRequests.
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+                    if (nri.isRequest == false) continue;
                     NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                     ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK,
                             (nai != null ? nai.currentScore : 0), 0, nri.request);
                 }
             } else {
                 loge("Error connecting NetworkFactory");
-                mNetworkFactories.remove(ac);
+                mNetworkFactoryInfos.remove(msg.obj);
             }
         } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
             if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
@@ -3214,8 +3231,8 @@
         mNetworkRequests.put(nri.request, nri);
         if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
             if (DBG) log("sending new NetworkRequest to factories");
-            for (AsyncChannel ac : mNetworkFactories) {
-                ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+            for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
+                nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
             }
         }
     }
@@ -3236,8 +3253,8 @@
             }
 
             if (nri.isRequest) {
-                for (AsyncChannel factory : mNetworkFactories) {
-                    factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request);
+                for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
+                    nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request);
                 }
 
                 if (affectedNetwork != null) {
@@ -3356,7 +3373,11 @@
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_FACTORY: {
-                    handleRegisterNetworkFactory((Messenger)msg.obj);
+                    handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
+                    break;
+                }
+                case EVENT_UNREGISTER_NETWORK_FACTORY: {
+                    handleUnregisterNetworkFactory((Messenger)msg.obj);
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_AGENT: {
@@ -5222,10 +5243,22 @@
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
     }
 
-    private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>();
+    private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
+            new HashMap<Messenger, NetworkFactoryInfo>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
             new HashMap<NetworkRequest, NetworkRequestInfo>();
 
+    private static class NetworkFactoryInfo {
+        public final String name;
+        public final Messenger messenger;
+        public final AsyncChannel asyncChannel;
+
+        public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) {
+            this.name = name;
+            this.messenger = messenger;
+            this.asyncChannel = asyncChannel;
+        }
+    }
 
     private class NetworkRequestInfo implements IBinder.DeathRecipient {
         static final boolean REQUEST = true;
@@ -5263,6 +5296,11 @@
                     request + ", " + mBinder + ")");
             releaseNetworkRequest(request);
         }
+
+        public String toString() {
+            return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" +
+                    mPid + " for " + request;
+        }
     }
 
     @Override
@@ -5326,24 +5364,31 @@
     }
 
     @Override
-    public void registerNetworkFactory(Messenger messenger) {
+    public void registerNetworkFactory(Messenger messenger, String name) {
         enforceConnectivityInternalPermission();
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger));
+        NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
     }
 
-    private void handleRegisterNetworkFactory(Messenger messenger) {
-        if (VDBG) log("Got NetworkFactory Messenger");
-        AsyncChannel ac = new AsyncChannel();
-        mNetworkFactories.add(ac);
-        ac.connect(mContext, mTrackerHandler, messenger);
-        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-            if (nri.isRequest) {
-                int score = 0;
-                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
-                if (currentNetwork != null) score = currentNetwork.currentScore;
-                ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
-            }
+    private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
+        if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name);
+        mNetworkFactoryInfos.put(nfi.messenger, nfi);
+        nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
+    }
+
+    @Override
+    public void unregisterNetworkFactory(Messenger messenger) {
+        enforceConnectivityInternalPermission();
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
+    }
+
+    private void handleUnregisterNetworkFactory(Messenger messenger) {
+        NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
+        if (nfi == null) {
+            if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory");
+            return;
         }
+        if (VDBG) log("unregisterNetworkFactory for " + nfi.name);
     }
 
     /**
@@ -5535,8 +5580,8 @@
 
     private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
         if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
-        for (AsyncChannel ac : mNetworkFactories) {
-            ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest);
+        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
+            nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest);
         }
     }
 
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 50553ee..5cb2a8a6f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -3439,7 +3439,7 @@
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
                     + " mShowForced=" + mShowForced
                     + " mInputShown=" + mInputShown);
-            p.println("  mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn);
+            p.println("  mSystemReady=" + mSystemReady + " mInteractive=" + mScreenOn);
         }
 
         p.println(" ");
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index c32beda..cd8c13fb 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -264,7 +264,7 @@
             } else if (headset == BIT_USB_HEADSET_DGTL) {
                 device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
             } else if (headset == BIT_HDMI_AUDIO) {
-                device = AudioManager.DEVICE_OUT_AUX_DIGITAL;
+                device = AudioManager.DEVICE_OUT_HDMI;
             } else {
                 Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
                 return;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7abc75f..7cd4ef8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13837,7 +13837,7 @@
         }
 
         if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
-            ProxyInfo proxy = intent.getParcelableExtra("proxy");
+            ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
             mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
         }
 
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index e0bc718..156bbbe 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -103,7 +103,7 @@
                 requestVendorId();
                 return true;
             } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
-                int requestOpcode = params[1];
+                int requestOpcode = params[1] & 0xff;
                 if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
                     mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
                     requestVendorId();
@@ -113,7 +113,8 @@
         } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
             if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
                 if (params.length == 3) {
-                    mVendorId = (params[0] << 16) + (params[1] << 8) + params[2];
+                    mVendorId = ((params[0] & 0xff) << 16) + ((params[1] & 0xff) << 8)
+                        + (params[2] & 0xff);
                 } else {
                     Slog.e(TAG, "Failed to get device vendor ID: ");
                 }
@@ -121,7 +122,7 @@
                 finish();
                 return true;
             } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
-                int requestOpcode = params[1];
+                int requestOpcode = params[1] & 0xff;
                 if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
                     addDeviceInfo();
                     finish();
diff --git a/services/core/java/com/android/server/net/DelayedDiskWrite.java b/services/core/java/com/android/server/net/DelayedDiskWrite.java
new file mode 100644
index 0000000..6ed277d
--- /dev/null
+++ b/services/core/java/com/android/server/net/DelayedDiskWrite.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class DelayedDiskWrite {
+    private HandlerThread mDiskWriteHandlerThread;
+    private Handler mDiskWriteHandler;
+    /* Tracks multiple writes on the same thread */
+    private int mWriteSequence = 0;
+    private final String TAG = "DelayedDiskWrite";
+
+    public interface Writer {
+        public void onWriteCalled(DataOutputStream out) throws IOException;
+    }
+
+    public void write(final String filePath, final Writer w) {
+        if (TextUtils.isEmpty(filePath)) {
+            throw new IllegalArgumentException("empty file path");
+        }
+
+        /* Do a delayed write to disk on a separate handler thread */
+        synchronized (this) {
+            if (++mWriteSequence == 1) {
+                mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread");
+                mDiskWriteHandlerThread.start();
+                mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper());
+            }
+        }
+
+        mDiskWriteHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                doWrite(filePath, w);
+            }
+        });
+    }
+
+    private void doWrite(String filePath, Writer w) {
+        DataOutputStream out = null;
+        try {
+            out = new DataOutputStream(new BufferedOutputStream(
+                        new FileOutputStream(filePath)));
+            w.onWriteCalled(out);
+        } catch (IOException e) {
+            loge("Error writing data file " + filePath);
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (Exception e) {}
+            }
+
+            // Quit if no more writes sent
+            synchronized (this) {
+                if (--mWriteSequence == 0) {
+                    mDiskWriteHandler.getLooper().quit();
+                    mDiskWriteHandler = null;
+                    mDiskWriteHandlerThread = null;
+                }
+            }
+        }
+    }
+
+    private void loge(String s) {
+        Log.e(TAG, s);
+    }
+}
+
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
new file mode 100644
index 0000000..6ccbec0
--- /dev/null
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.server.net.DelayedDiskWrite;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Map;
+
+public class IpConfigStore {
+    private static final String TAG = "IpConfigStore";
+    private static final boolean DBG = true;
+
+    protected final DelayedDiskWrite mWriter;
+
+    /* IP and proxy configuration keys */
+    protected static final String ID_KEY = "id";
+    protected static final String IP_ASSIGNMENT_KEY = "ipAssignment";
+    protected static final String LINK_ADDRESS_KEY = "linkAddress";
+    protected static final String GATEWAY_KEY = "gateway";
+    protected static final String DNS_KEY = "dns";
+    protected static final String PROXY_SETTINGS_KEY = "proxySettings";
+    protected static final String PROXY_HOST_KEY = "proxyHost";
+    protected static final String PROXY_PORT_KEY = "proxyPort";
+    protected static final String PROXY_PAC_FILE = "proxyPac";
+    protected static final String EXCLUSION_LIST_KEY = "exclusionList";
+    protected static final String EOS = "eos";
+
+    protected static final int IPCONFIG_FILE_VERSION = 2;
+
+    public IpConfigStore() {
+        mWriter = new DelayedDiskWrite();
+    }
+
+    private boolean writeConfig(DataOutputStream out, int configKey,
+                                  IpConfiguration config) throws IOException {
+        boolean written = false;
+
+        try {
+            LinkProperties linkProperties = config.linkProperties;
+            switch (config.ipAssignment) {
+                case STATIC:
+                    out.writeUTF(IP_ASSIGNMENT_KEY);
+                    out.writeUTF(config.ipAssignment.toString());
+                    for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) {
+                        out.writeUTF(LINK_ADDRESS_KEY);
+                        out.writeUTF(linkAddr.getAddress().getHostAddress());
+                        out.writeInt(linkAddr.getNetworkPrefixLength());
+                    }
+                    for (RouteInfo route : linkProperties.getRoutes()) {
+                        out.writeUTF(GATEWAY_KEY);
+                        LinkAddress dest = route.getDestination();
+                        if (dest != null) {
+                            out.writeInt(1);
+                            out.writeUTF(dest.getAddress().getHostAddress());
+                            out.writeInt(dest.getNetworkPrefixLength());
+                        } else {
+                            out.writeInt(0);
+                        }
+                        if (route.getGateway() != null) {
+                            out.writeInt(1);
+                            out.writeUTF(route.getGateway().getHostAddress());
+                        } else {
+                            out.writeInt(0);
+                        }
+                    }
+                    for (InetAddress inetAddr : linkProperties.getDnses()) {
+                        out.writeUTF(DNS_KEY);
+                        out.writeUTF(inetAddr.getHostAddress());
+                    }
+                    written = true;
+                    break;
+                case DHCP:
+                    out.writeUTF(IP_ASSIGNMENT_KEY);
+                    out.writeUTF(config.ipAssignment.toString());
+                    written = true;
+                    break;
+                case UNASSIGNED:
+                /* Ignore */
+                    break;
+                default:
+                    loge("Ignore invalid ip assignment while writing");
+                    break;
+            }
+
+            switch (config.proxySettings) {
+                case STATIC:
+                    ProxyInfo proxyProperties = linkProperties.getHttpProxy();
+                    String exclusionList = proxyProperties.getExclusionListAsString();
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(PROXY_HOST_KEY);
+                    out.writeUTF(proxyProperties.getHost());
+                    out.writeUTF(PROXY_PORT_KEY);
+                    out.writeInt(proxyProperties.getPort());
+                    out.writeUTF(EXCLUSION_LIST_KEY);
+                    out.writeUTF(exclusionList);
+                    written = true;
+                    break;
+                case PAC:
+                    ProxyInfo proxyPacProperties = linkProperties.getHttpProxy();
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(PROXY_PAC_FILE);
+                    out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
+                    written = true;
+                    break;
+                case NONE:
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    written = true;
+                    break;
+                case UNASSIGNED:
+                    /* Ignore */
+                        break;
+                    default:
+                        loge("Ignore invalid proxy settings while writing");
+                        break;
+            }
+
+            if (written) {
+                out.writeUTF(ID_KEY);
+                out.writeInt(configKey);
+            }
+        } catch (NullPointerException e) {
+            loge("Failure in writing " + config.linkProperties + e);
+        }
+        out.writeUTF(EOS);
+
+        return written;
+    }
+
+    public void writeIpAndProxyConfigurations(String filePath,
+                                              final SparseArray<IpConfiguration> networks) {
+        mWriter.write(filePath, new DelayedDiskWrite.Writer() {
+            public void onWriteCalled(DataOutputStream out) throws IOException{
+                out.writeInt(IPCONFIG_FILE_VERSION);
+                for(int i = 0; i < networks.size(); i++) {
+                    writeConfig(out, networks.keyAt(i), networks.valueAt(i));
+                }
+            }
+        });
+    }
+
+    public SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) {
+        SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
+
+        DataInputStream in = null;
+        try {
+            in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));
+
+            int version = in.readInt();
+            if (version != 2 && version != 1) {
+                loge("Bad version on IP configuration file, ignore read");
+                return null;
+            }
+
+            while (true) {
+                int id = -1;
+                // Default is DHCP with no proxy
+                IpAssignment ipAssignment = IpAssignment.DHCP;
+                ProxySettings proxySettings = ProxySettings.NONE;
+                LinkProperties linkProperties = new LinkProperties();
+                String proxyHost = null;
+                String pacFileUrl = null;
+                int proxyPort = -1;
+                String exclusionList = null;
+                String key;
+
+                do {
+                    key = in.readUTF();
+                    try {
+                        if (key.equals(ID_KEY)) {
+                            id = in.readInt();
+                        } else if (key.equals(IP_ASSIGNMENT_KEY)) {
+                            ipAssignment = IpAssignment.valueOf(in.readUTF());
+                        } else if (key.equals(LINK_ADDRESS_KEY)) {
+                            LinkAddress linkAddr = new LinkAddress(
+                                    NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
+                            linkProperties.addLinkAddress(linkAddr);
+                        } else if (key.equals(GATEWAY_KEY)) {
+                            LinkAddress dest = null;
+                            InetAddress gateway = null;
+                            if (version == 1) {
+                                // only supported default gateways - leave the dest/prefix empty
+                                gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                            } else {
+                                if (in.readInt() == 1) {
+                                    dest = new LinkAddress(
+                                            NetworkUtils.numericToInetAddress(in.readUTF()),
+                                            in.readInt());
+                                }
+                                if (in.readInt() == 1) {
+                                    gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                                }
+                            }
+                            linkProperties.addRoute(new RouteInfo(dest, gateway));
+                        } else if (key.equals(DNS_KEY)) {
+                            linkProperties.addDns(
+                                    NetworkUtils.numericToInetAddress(in.readUTF()));
+                        } else if (key.equals(PROXY_SETTINGS_KEY)) {
+                            proxySettings = ProxySettings.valueOf(in.readUTF());
+                        } else if (key.equals(PROXY_HOST_KEY)) {
+                            proxyHost = in.readUTF();
+                        } else if (key.equals(PROXY_PORT_KEY)) {
+                            proxyPort = in.readInt();
+                        } else if (key.equals(PROXY_PAC_FILE)) {
+                            pacFileUrl = in.readUTF();
+                        } else if (key.equals(EXCLUSION_LIST_KEY)) {
+                            exclusionList = in.readUTF();
+                        } else if (key.equals(EOS)) {
+                            break;
+                        } else {
+                            loge("Ignore unknown key " + key + "while reading");
+                        }
+                    } catch (IllegalArgumentException e) {
+                        loge("Ignore invalid address while reading" + e);
+                    }
+                } while (true);
+
+                if (id != -1) {
+                    IpConfiguration config = new IpConfiguration();
+                    networks.put(id, config);
+
+                    config.linkProperties = linkProperties;
+                    switch (ipAssignment) {
+                        case STATIC:
+                        case DHCP:
+                            config.ipAssignment = ipAssignment;
+                            break;
+                        case UNASSIGNED:
+                            loge("BUG: Found UNASSIGNED IP on file, use DHCP");
+                            config.ipAssignment = IpAssignment.DHCP;
+                            break;
+                        default:
+                            loge("Ignore invalid ip assignment while reading.");
+                            config.ipAssignment = IpAssignment.UNASSIGNED;
+                            break;
+                    }
+
+                    switch (proxySettings) {
+                        case STATIC:
+                            config.proxySettings = proxySettings;
+                            ProxyInfo ProxyInfo =
+                                    new ProxyInfo(proxyHost, proxyPort, exclusionList);
+                            linkProperties.setHttpProxy(ProxyInfo);
+                            break;
+                        case PAC:
+                            config.proxySettings = proxySettings;
+                            ProxyInfo proxyPacProperties =
+                                    new ProxyInfo(pacFileUrl);
+                            linkProperties.setHttpProxy(proxyPacProperties);
+                            break;
+                        case NONE:
+                            config.proxySettings = proxySettings;
+                            break;
+                        case UNASSIGNED:
+                            loge("BUG: Found UNASSIGNED proxy on file, use NONE");
+                            config.proxySettings = ProxySettings.NONE;
+                            break;
+                        default:
+                            loge("Ignore invalid proxy settings while reading");
+                            config.proxySettings = ProxySettings.UNASSIGNED;
+                            break;
+                    }
+                } else {
+                    if (DBG) log("Missing id while parsing configuration");
+                }
+            }
+        } catch (EOFException ignore) {
+        } catch (IOException e) {
+            loge("Error parsing configuration" + e);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (Exception e) {}
+            }
+        }
+
+        return networks;
+    }
+
+    protected void loge(String s) {
+        Log.e(TAG, s);
+    }
+
+    protected void log(String s) {
+        Log.d(TAG, s);
+    }
+}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 007032e..dbfb1cf 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -88,6 +88,8 @@
             for (int i = 0; i < mRecords.size(); i++) {
                 pw.print("      "); pw.println(mRecords.get(i));
             }
+            pw.print("    mCountdownHelper: ");
+            pw.println(mCountdownHelper.getCurrentConditionDescription());
         }
     }
 
@@ -474,6 +476,16 @@
             }
         }
 
+        public String getCurrentConditionDescription() {
+            if (mCurrent == 0) return null;
+            final long time = mCurrent;
+            final long now = System.currentTimeMillis();
+            final CharSequence span =
+                    DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
+            return String.format("Scheduled for %s, %s in the future (%s), now=%s",
+                    ts(time), time - now, span, ts(now));
+        }
+
         private String ts(long time) {
             return new Date(time) + " (" + time + ")";
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1734a33..9569c0d1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -63,7 +63,7 @@
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
 import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationOrderUpdate;
+import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
@@ -1744,7 +1744,7 @@
                             sendAccessibilityEvent(notification, pkg);
                         }
 
-                        mListeners.notifyPostedLocked(r.sbn);
+                        mListeners.notifyPostedLocked(r.sbn, cloneNotificationListLocked());
                     } else {
                         Slog.e(TAG, "Not posting notification with icon==0: " + notification);
                         if (old != null && old.statusBarKey != null) {
@@ -1755,7 +1755,7 @@
                                 Binder.restoreCallingIdentity(identity);
                             }
 
-                            mListeners.notifyRemovedLocked(r.sbn);
+                            mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked());
                         }
                         // ATTENTION: in a future release we will bail out here
                         // so that we do not play sounds, show lights, etc. for invalid
@@ -2041,16 +2041,19 @@
 
     private void handleSendRankingUpdate() {
         synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            ArrayList<StatusBarNotification> sbns =
-                    new ArrayList<StatusBarNotification>(N);
-            for (int i = 0; i < N; i++ ) {
-                sbns.add(mNotificationList.get(i).sbn);
-            }
-            mListeners.notifyOrderUpdateLocked(sbns);
+            mListeners.notifyRankingUpdateLocked(cloneNotificationListLocked());
         }
     }
 
+    private ArrayList<StatusBarNotification> cloneNotificationListLocked() {
+        final int N = mNotificationList.size();
+        ArrayList<StatusBarNotification> sbns = new ArrayList<StatusBarNotification>(N);
+        for (int i = 0; i < N; i++) {
+            sbns.add(mNotificationList.get(i).sbn);
+        }
+        return sbns;
+    }
+
     private final class WorkerHandler extends Handler
     {
         @Override
@@ -2136,7 +2139,7 @@
                 Binder.restoreCallingIdentity(identity);
             }
             r.statusBarKey = null;
-            mListeners.notifyRemovedLocked(r.sbn);
+            mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked());
         }
 
         // sound
@@ -2442,6 +2445,33 @@
         }
     }
 
+    /**
+     * Generates a NotificationRankingUpdate from 'sbns', considering only
+     * notifications visible to the given listener.
+     */
+    private static NotificationRankingUpdate makeRankingUpdateForListener(ManagedServiceInfo info,
+            ArrayList<StatusBarNotification> sbns) {
+        int speedBumpIndex = -1;
+        ArrayList<String> keys = new ArrayList<String>(sbns.size());
+        ArrayList<String> dndKeys = new ArrayList<String>(sbns.size());
+        for (StatusBarNotification sbn: sbns) {
+            if (!info.enabledAndUserMatches(sbn.getUserId())) {
+                continue;
+            }
+            keys.add(sbn.getKey());
+            if (sbn.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) {
+                dndKeys.add(sbn.getKey());
+            }
+            if (speedBumpIndex == -1 &&
+                    sbn.getNotification().priority == Notification.PRIORITY_MIN) {
+                speedBumpIndex = keys.size() - 1;
+            }
+        }
+        String[] keysAr = keys.toArray(new String[keys.size()]);
+        String[] dndKeysAr = dndKeys.toArray(new String[dndKeys.size()]);
+        return new NotificationRankingUpdate(keysAr, dndKeysAr, speedBumpIndex);
+    }
+
     public class NotificationListeners extends ManagedServices {
 
         public NotificationListeners() {
@@ -2468,9 +2498,12 @@
         @Override
         public void onServiceAdded(ManagedServiceInfo info) {
             final INotificationListener listener = (INotificationListener) info.service;
-            final String[] keys = getActiveNotificationKeys(listener);
+            final ArrayList<StatusBarNotification> sbns;
+            synchronized (mNotificationList) {
+                sbns = cloneNotificationListLocked();
+            }
             try {
-                listener.onListenerConnected(new NotificationOrderUpdate(keys));
+                listener.onListenerConnected(makeRankingUpdateForListener(info, sbns));
             } catch (RemoteException e) {
                 // we tried
             }
@@ -2479,44 +2512,47 @@
         /**
          * asynchronously notify all listeners about a new notification
          */
-        public void notifyPostedLocked(StatusBarNotification sbn) {
+        public void notifyPostedLocked(StatusBarNotification sbn,
+                final ArrayList<StatusBarNotification> sbns) {
             // make a copy in case changes are made to the underlying Notification object
             final StatusBarNotification sbnClone = sbn.clone();
             for (final ManagedServiceInfo info : mServices) {
-                if (info.isEnabledForCurrentProfiles()) {
-                    final INotificationListener listener = (INotificationListener) info.service;
-                    final String[] keys = getActiveNotificationKeys(listener);
-                    if (keys.length > 0) {
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                notifyPostedIfUserMatch(info, sbnClone, keys);
-                            }
-                        });
-                    }
+                if (!info.isEnabledForCurrentProfiles()) {
+                    continue;
                 }
+                final NotificationRankingUpdate update = makeRankingUpdateForListener(info, sbns);
+                if (update.getOrderedKeys().length == 0) {
+                    continue;
+                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        notifyPostedIfUserMatch(info, sbnClone, update);
+                    }
+                });
             }
         }
 
         /**
          * asynchronously notify all listeners about a removed notification
          */
-        public void notifyRemovedLocked(StatusBarNotification sbn) {
+        public void notifyRemovedLocked(StatusBarNotification sbn,
+                final ArrayList<StatusBarNotification> sbns) {
             // make a copy in case changes are made to the underlying Notification object
             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
             // notification
             final StatusBarNotification sbnLight = sbn.cloneLight();
             for (final ManagedServiceInfo info : mServices) {
-                if (info.isEnabledForCurrentProfiles()) {
-                    final INotificationListener listener = (INotificationListener) info.service;
-                    final String[] keys = getActiveNotificationKeys(listener);
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            notifyRemovedIfUserMatch(info, sbnLight, keys);
-                        }
-                    });
+                if (!info.isEnabledForCurrentProfiles()) {
+                    continue;
                 }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        notifyRemovedIfUserMatch(info, sbnLight,
+                                makeRankingUpdateForListener(info, sbns));
+                    }
+                });
             }
         }
 
@@ -2526,60 +2562,52 @@
          *             must not rely on mutable members of these objects, such as the
          *             {@link Notification}.
          */
-        public void notifyOrderUpdateLocked(final ArrayList<StatusBarNotification> sbns) {
+        public void notifyRankingUpdateLocked(final ArrayList<StatusBarNotification> sbns) {
             for (final ManagedServiceInfo serviceInfo : mServices) {
+                if (!serviceInfo.isEnabledForCurrentProfiles()) {
+                    continue;
+                }
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        notifyOrderUpdateIfUserMatch(serviceInfo, sbns);
+                        notifyRankingUpdate(serviceInfo,
+                                makeRankingUpdateForListener(serviceInfo, sbns));
                     }
                 });
             }
         }
 
         private void notifyPostedIfUserMatch(final ManagedServiceInfo info,
-                final StatusBarNotification sbn, String[] keys) {
+                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
             if (!info.enabledAndUserMatches(sbn.getUserId())) {
                 return;
             }
             final INotificationListener listener = (INotificationListener)info.service;
             try {
-                listener.onNotificationPosted(sbn, new NotificationOrderUpdate(keys));
+                listener.onNotificationPosted(sbn, rankingUpdate);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
             }
         }
 
         private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn,
-                String[] keys) {
+                NotificationRankingUpdate rankingUpdate) {
             if (!info.enabledAndUserMatches(sbn.getUserId())) {
                 return;
             }
-            final INotificationListener listener = (INotificationListener)info.service;
+            final INotificationListener listener = (INotificationListener) info.service;
             try {
-                listener.onNotificationRemoved(sbn, new NotificationOrderUpdate(keys));
+                listener.onNotificationRemoved(sbn, rankingUpdate);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
             }
         }
 
-        /**
-         * @param sbns an array of {@link StatusBarNotification}s to consider.  This code
-         *             must not rely on mutable members of these objects, such as the
-         *             {@link Notification}.
-         */
-        public void notifyOrderUpdateIfUserMatch(ManagedServiceInfo info,
-                ArrayList<StatusBarNotification> sbns) {
-            ArrayList<String> keys = new ArrayList<String>(sbns.size());
-            for (StatusBarNotification sbn: sbns) {
-                if (info.enabledAndUserMatches(sbn.getUserId())) {
-                    keys.add(sbn.getKey());
-                }
-            }
-            final INotificationListener listener = (INotificationListener)info.service;
+        private void notifyRankingUpdate(ManagedServiceInfo info,
+                                         NotificationRankingUpdate rankingUpdate) {
+            final INotificationListener listener = (INotificationListener) info.service;
             try {
-                listener.onNotificationOrderUpdate(
-                        new NotificationOrderUpdate(keys.toArray(new String[keys.size()])));
+                listener.onNotificationRankingUpdate(rankingUpdate);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 61b3a89..46c5482 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11876,6 +11876,7 @@
                 pw.println("  cmd may be one of:");
                 pw.println("    l[ibraries]: list known shared libraries");
                 pw.println("    f[ibraries]: list device features");
+                pw.println("    k[eysets]: print known keysets");
                 pw.println("    r[esolvers]: dump intent resolvers");
                 pw.println("    perm[issions]: dump permissions");
                 pw.println("    pref[erred]: print preferred package settings");
@@ -11886,8 +11887,8 @@
                 pw.println("    m[essages]: print collected runtime messages");
                 pw.println("    v[erifiers]: print package verifier info");
                 pw.println("    version: print database version info");
+                pw.println("    write: write current settings now");
                 pw.println("    <package.name>: info about given package");
-                pw.println("    k[eysets]: print known keysets");
                 return;
             } else if ("--checkin".equals(opt)) {
                 checkin = true;
@@ -11938,6 +11939,12 @@
                 dumpState.setDump(DumpState.DUMP_VERSION);
             } else if ("k".equals(cmd) || "keysets".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_KEYSETS);
+            } else if ("write".equals(cmd)) {
+                synchronized (mPackages) {
+                    mSettings.writeLPr();
+                    pw.println("Settings written.");
+                    return;
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 131d05b..102b2d4 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -511,8 +511,16 @@
      * Check if we've hit the limit of how many users can be created.
      */
     private boolean isUserLimitReachedLocked() {
-        int nUsers = mUsers.size();
-        return nUsers >= UserManager.getMaxSupportedUsers();
+        int aliveUserCount = 0;
+        final int totalUserCount = mUsers.size();
+        // Skip over users being removed
+        for (int i = 0; i < totalUserCount; i++) {
+            UserInfo user = mUsers.valueAt(i);
+            if (!mRemovingUserIds.get(user.id)) {
+                aliveUserCount++;
+            }
+        }
+        return aliveUserCount >= UserManager.getMaxSupportedUsers();
     }
 
     /**
@@ -781,6 +789,7 @@
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_TELEPHONY);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -933,6 +942,7 @@
                                 UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_TELEPHONY);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c1b9a33..efaa91b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -324,8 +324,6 @@
                 mTrustListeners.get(i).onTrustChanged(enabled, userId);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Exception while notifying TrustListener. Removing listener.", e);
-                mTrustListeners.get(i);
-                i--;
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c20e38c..e2d2ac6 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -26,6 +26,7 @@
 import android.os.IRemoteCallback;
 import android.os.SystemProperties;
 import android.util.Slog;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -34,7 +35,6 @@
 import android.view.animation.ClipRectAnimation;
 import android.view.animation.Interpolator;
 import android.view.animation.ScaleAnimation;
-
 import android.view.animation.TranslateAnimation;
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.server.AttributeCache;
@@ -500,7 +500,8 @@
      */
     Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
                                                     int appHeight, int orientation, int transit,
-                                                    Rect containingFrame, Rect contentInsets) {
+                                                    Rect containingFrame, Rect contentInsets,
+                                                    boolean isFullScreen) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -520,6 +521,9 @@
                     scaledTopDecor = (int) (scale * contentInsets.top);
                     int unscaledThumbHeight = (int) (thumbHeight / scale);
                     mTmpFromClipRect.set(containingFrame);
+                    if (isFullScreen) {
+                        mTmpFromClipRect.top = contentInsets.top;
+                    }
                     mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
                     mTmpToClipRect.set(containingFrame);
                 } else {
@@ -527,7 +531,12 @@
                     scale = thumbHeight / (appHeight - contentInsets.top);
                     scaledTopDecor = (int) (scale * contentInsets.top);
                     int unscaledThumbWidth = (int) (thumbWidth / scale);
+                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                     mTmpFromClipRect.set(containingFrame);
+                    if (isFullScreen) {
+                        mTmpFromClipRect.top = contentInsets.top;
+                        mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
+                    }
                     mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
                     mTmpToClipRect.set(containingFrame);
                 }
@@ -575,14 +584,22 @@
                     int unscaledThumbHeight = (int) (thumbHeight / scale);
                     mTmpFromClipRect.set(containingFrame);
                     mTmpToClipRect.set(containingFrame);
+                    if (isFullScreen) {
+                        mTmpToClipRect.top = contentInsets.top;
+                    }
                     mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
                 } else {
                     // In landscape, we scale the height and clip to the top/left square
                     scale = thumbHeight / (appHeight - contentInsets.top);
                     scaledTopDecor = (int) (scale * contentInsets.top);
                     int unscaledThumbWidth = (int) (thumbWidth / scale);
+                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                     mTmpFromClipRect.set(containingFrame);
                     mTmpToClipRect.set(containingFrame);
+                    if (isFullScreen) {
+                        mTmpToClipRect.top = contentInsets.top;
+                        mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
+                    }
                     mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth);
                 }
 
@@ -679,7 +696,7 @@
 
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                             int appWidth, int appHeight, int orientation,
-                            Rect containingFrame, Rect contentInsets) {
+                            Rect containingFrame, Rect contentInsets, boolean isFullScreen) {
         Animation a;
         if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -702,7 +719,7 @@
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
             a = createAlternateThumbnailEnterExitAnimationLocked(
                     getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
-                    transit, containingFrame, contentInsets);
+                    transit, containingFrame, contentInsets, isFullScreen);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c6fffbf..63a4f52 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -289,6 +289,11 @@
 
     private static final int MAX_SCREENSHOT_RETRIES = 3;
 
+    // The flag describing a full screen app window (where the app takes care of drawing under the
+    // SystemUI bars)
+    private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN =
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -3193,8 +3198,11 @@
                 }
             }
 
+            boolean isFullScreen =
+                    ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
+                            == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
-                    mCurConfiguration.orientation, containingFrame, contentInsets);
+                    mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e2cd4e2..bc7742f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3384,6 +3384,93 @@
     }
 
     @Override
+    public boolean setApplicationBlocked(ComponentName who, String packageName,
+            boolean blocked) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                return pm.setApplicationBlockedSettingAsUser(packageName, blocked, callingUserId);
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to setApplicationBlockedSetting", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public int setApplicationsBlocked(ComponentName who, Intent intent, boolean blocked) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                        PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_UNINSTALLED_PACKAGES,
+                        callingUserId);
+
+                if (DBG) Slog.d(LOG_TAG, "Enabling activities: " + activitiesToEnable);
+                int numberOfAppsUnblocked = 0;
+                if (activitiesToEnable != null) {
+                    for (ResolveInfo info : activitiesToEnable) {
+                        if (info.activityInfo != null) {
+                            numberOfAppsUnblocked++;
+                            pm.setApplicationBlockedSettingAsUser(info.activityInfo.packageName,
+                                    blocked, callingUserId);
+                        }
+                    }
+                }
+                return numberOfAppsUnblocked;
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to setApplicationsBlockedSettingsWithIntent", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return 0;
+        }
+    }
+
+    @Override
+    public boolean isApplicationBlocked(ComponentName who, String packageName) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                return pm.getApplicationBlockedSettingAsUser(packageName, callingUserId);
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to getApplicationBlockedSettingAsUser", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
     public void enableSystemApp(ComponentName who, String packageName) {
         synchronized (this) {
             if (who == null) {
@@ -3595,4 +3682,43 @@
         }
         return false;
     }
+
+    @Override
+    public void setGlobalSetting(ComponentName who, String setting, String value) {
+        final ContentResolver contentResolver = mContext.getContentResolver();
+
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                Settings.Global.putString(contentResolver, setting, value);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    @Override
+    public void setSecureSetting(ComponentName who, String setting, String value) {
+        int callingUserId = UserHandle.getCallingUserId();
+        final ContentResolver contentResolver = mContext.getContentResolver();
+
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9b3f7ac..55ae9c6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -125,7 +125,7 @@
     private static final String WIFI_SERVICE_CLASS =
             "com.android.server.wifi.WifiService";
     private static final String WIFI_PASSPOINT_SERVICE_CLASS =
-            "com.android.server.wifi.passpoint.WifiPasspointService";
+            "com.android.server.wifi.passpoint.PasspointService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String HDMI_CEC_SERVICE_CLASS =
@@ -639,18 +639,18 @@
                 }
 
                 try {
-                    mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
-                } catch (Throwable e) {
-                    reportWtf("starting Wi-Fi PasspointService", e);
-                }
-
-                try {
                     mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
                 } catch (Throwable e) {
                     reportWtf("starting Wi-Fi Service", e);
                 }
 
                 try {
+                    mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi PasspointService", e);
+                }
+
+                try {
                     Slog.i(TAG, "Wi-Fi Scanning Service");
                     mSystemServiceManager.startService(
                             "com.android.server.wifi.WifiScanningService");
diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk
index bdcba2e..e07e943 100644
--- a/tests/RenderThreadTest/Android.mk
+++ b/tests/RenderThreadTest/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/RenderThreadTest/AndroidManifest.xml
index c76cfce..a7f4f6e 100644
--- a/tests/RenderThreadTest/AndroidManifest.xml
+++ b/tests/RenderThreadTest/AndroidManifest.xml
@@ -4,10 +4,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk
-        android:minSdkVersion="18"
-        android:targetSdkVersion="18" />
-
     <application
         android:allowBackup="true"
         android:icon="@drawable/ic_launcher"
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e73cce1b..292f844 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -16,9 +16,13 @@
 
 package android.net.wifi;
 
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.ProxyInfo;
 import android.net.LinkProperties;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.text.TextUtils;
 
 import java.util.HashMap;
@@ -286,20 +290,7 @@
     /**
      * @hide
      */
-    public enum IpAssignment {
-        /* Use statically configured IP settings. Configuration can be accessed
-         * with linkProperties */
-        STATIC,
-        /* Use dynamically configured IP settigns */
-        DHCP,
-        /* no IP details are assigned, this is used to indicate
-         * that any existing IP settings should be retained */
-        UNASSIGNED
-    }
-    /**
-     * @hide
-     */
-    public IpAssignment ipAssignment;
+    private IpConfiguration mIpConfiguration;
 
     /**
      * @hide
@@ -457,32 +448,6 @@
      */
     public HashMap<String, Integer>  linkedConfigurations;
 
-    /**
-     * @hide
-     */
-    public enum ProxySettings {
-        /* No proxy is to be used. Any existing proxy settings
-         * should be cleared. */
-        NONE,
-        /* Use statically configured proxy. Configuration can be accessed
-         * with linkProperties */
-        STATIC,
-        /* no proxy details are assigned, this is used to indicate
-         * that any existing proxy settings should be retained */
-        UNASSIGNED,
-        /* Use a Pac based proxy.
-         */
-        PAC
-    }
-    /**
-     * @hide
-     */
-    public ProxySettings proxySettings;
-    /**
-     * @hide
-     */
-    public LinkProperties linkProperties;
-
     public WifiConfiguration() {
         networkId = INVALID_NETWORK_ID;
         SSID = null;
@@ -500,12 +465,10 @@
             wepKeys[i] = null;
         }
         enterpriseConfig = new WifiEnterpriseConfig();
-        ipAssignment = IpAssignment.UNASSIGNED;
-        proxySettings = ProxySettings.UNASSIGNED;
-        linkProperties = new LinkProperties();
         autoJoinStatus = AUTO_JOIN_ENABLED;
         selfAdded = false;
         ephemeral = false;
+        mIpConfiguration = new IpConfiguration();
     }
 
     /**
@@ -640,12 +603,7 @@
         sbuf.append(enterpriseConfig);
         sbuf.append('\n');
 
-        sbuf.append("IP assignment: " + ipAssignment.toString());
-        sbuf.append("\n");
-        sbuf.append("Proxy settings: " + proxySettings.toString());
-        sbuf.append("\n");
-        sbuf.append(linkProperties.toString());
-        sbuf.append("\n");
+        sbuf.append(mIpConfiguration.toString());
 
         return sbuf.toString();
     }
@@ -823,6 +781,52 @@
         return key;
     }
 
+    /** @hide */
+    public IpConfiguration getIpConfiguration() {
+        return mIpConfiguration;
+    }
+
+    /** @hide */
+    public void setIpConfiguration(IpConfiguration ipConfiguration) {
+        mIpConfiguration = ipConfiguration;
+    }
+
+    /** @hide */
+    public LinkProperties getLinkProperties() {
+        return mIpConfiguration.linkProperties;
+    }
+
+    /** @hide */
+    public void setLinkProperties(LinkProperties linkProperties) {
+        mIpConfiguration.linkProperties = linkProperties;
+    }
+
+    /** @hide */
+    public IpConfiguration.IpAssignment getIpAssignment() {
+        return mIpConfiguration.ipAssignment;
+    }
+
+    /** @hide */
+    public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
+        mIpConfiguration.ipAssignment = ipAssignment;
+    }
+
+    /** @hide */
+    public IpConfiguration.ProxySettings getProxySettings() {
+        return mIpConfiguration.proxySettings;
+    }
+
+    /** @hide */
+    public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
+        mIpConfiguration.proxySettings = proxySettings;
+    }
+
+    /** @hide */
+    public void setProxy(ProxySettings settings, ProxyInfo proxy) {
+        mIpConfiguration.proxySettings = settings;
+        mIpConfiguration.linkProperties.setHttpProxy(proxy);
+    }
+
     /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
@@ -854,12 +858,10 @@
 
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
-            ipAssignment = source.ipAssignment;
-            proxySettings = source.proxySettings;
-
             defaultGwMacAddress = source.defaultGwMacAddress;
 
-            linkProperties = new LinkProperties(source.linkProperties);
+            mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
+
             if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
                 scanResultCache = new HashMap<String, ScanResult>();
                 scanResultCache.putAll(source.scanResultCache);
@@ -882,10 +884,11 @@
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
             }
-       }
+        }
     }
 
     /** Implement the Parcelable interface {@hide} */
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(networkId);
         dest.writeInt(status);
@@ -908,10 +911,7 @@
 
         dest.writeParcelable(enterpriseConfig, flags);
 
-        dest.writeString(ipAssignment.name());
-        dest.writeString(proxySettings.name());
-        dest.writeParcelable(linkProperties, flags);
-
+        dest.writeParcelable(mIpConfiguration, flags);
         dest.writeString(dhcpServer);
         dest.writeString(defaultGwMacAddress);
         dest.writeInt(autoJoinStatus);
@@ -943,10 +943,7 @@
 
                 config.enterpriseConfig = in.readParcelable(null);
 
-                config.ipAssignment = IpAssignment.valueOf(in.readString());
-                config.proxySettings = ProxySettings.valueOf(in.readString());
-                config.linkProperties = in.readParcelable(null);
-
+                config.mIpConfiguration = in.readParcelable(null);
                 config.dhcpServer = in.readString();
                 config.defaultGwMacAddress = in.readString();
                 config.autoJoinStatus = in.readInt();