Merge "Keep bubbles behind a flag"
diff --git a/api/current.txt b/api/current.txt
index 223eb20..3d77ffb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3802,6 +3802,7 @@
     method @Deprecated public void onStateNotSaved();
     method @CallSuper protected void onStop();
     method protected void onTitleChanged(CharSequence, int);
+    method public void onTopResumedActivityChanged(boolean);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public void onTrimMemory(int);
@@ -14167,6 +14168,7 @@
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
     field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_JPEG = 1768253795; // 0x69656963
     field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int FLEX_RGBA_8888 = 42; // 0x2a
     field public static final int FLEX_RGB_888 = 41; // 0x29
@@ -16171,6 +16173,7 @@
     method public long getUsage();
     method public int getWidth();
     method public boolean isClosed();
+    method public static boolean isSupported(int, int, int, int, long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int BLOB = 33; // 0x21
     field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index 328b6d2..e0af359 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5743,6 +5743,12 @@
     field public static final String NAMESPACE = "activity_manager";
   }
 
+  public static interface DeviceConfig.AttentionManagerService {
+    field public static final String NAMESPACE = "attention_manager_service";
+    field public static final String PROPERTY_COMPONENT_NAME = "component_name";
+    field public static final String PROPERTY_SERVICE_ENABLED = "service_enabled";
+  }
+
   public static interface DeviceConfig.FsiBoot {
     field public static final String NAMESPACE = "fsi_boot";
     field public static final String OOB_ENABLED = "oob_enabled";
@@ -5751,8 +5757,8 @@
 
   public static interface DeviceConfig.IntelligenceAttention {
     field public static final String NAMESPACE = "intelligence_attention";
-    field public static final String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
-    field public static final String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+    field public static final String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
+    field public static final String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
   }
 
   public static interface DeviceConfig.OnPropertyChangedListener {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8e56bef..812a2f2 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -24,15 +24,18 @@
 import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/app/settings_enums.proto";
 import "frameworks/base/core/proto/android/app/job/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/a2dp/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto";
 import "frameworks/base/core/proto/android/debug/enums.proto";
 import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
 import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
 import "frameworks/base/core/proto/android/service/usb.proto";
@@ -213,6 +216,24 @@
         WatchdogRollbackOccurred watchdog_rollback_occurred = 147;
         BiometricHalDeathReported biometric_hal_death_reported = 148;
         BubbleUIChanged bubble_ui_changed = 149;
+        ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
+        BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
+        BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed = 152;
+        BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed = 153;
+        BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed = 154;
+        BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported = 155;
+        BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported = 156;
+        BluetoothDeviceRssiReported bluetooth_device_rssi_reported = 157;
+        BluetoothDeviceFailedContactCounterReported bluetooth_device_failed_contact_counter_reported = 158;
+        BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported = 159;
+        BluetoothHciTimeoutReported bluetooth_hci_timeout_reported = 160;
+        BluetoothQualityReportReported bluetooth_quality_report_reported = 161;
+        BluetoothManufacturerInfoReported bluetooth_device_info_reported = 162;
+        BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported = 163;
+        BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported = 164;
+        BluetoothBondStateChanged bluetooth_bond_state_changed = 165;
+        BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166;
+        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
     }
 
     // Pulled events will start at field 10000.
@@ -1407,6 +1428,27 @@
     optional android.bluetooth.hfp.ScoCodec codec = 3;
 }
 
+/**
+ * Logged when active device of a profile changes
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/hearingaid/HearingAidService.java
+ */
+message BluetoothActiveDeviceChanged {
+    // The profile whose active device has changed. Eg. A2DP, HEADSET, HEARING_AID
+    // From android.bluetooth.BluetoothProfile
+    optional int32 bt_profile = 1;
+    // An identifier that can be used to match events for this new active device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if there is no active device for this profile
+    optional bytes obfuscated_id = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
 // Logs when there is an event affecting Bluetooth device's link layer connection.
 // - This event is triggered when there is a related HCI command or event
 // - Users of this metrics can deduce Bluetooth device's connection state from these events
@@ -1509,6 +1551,516 @@
     optional int32 package_version_code = 3;
 }
 
+/**
+ * Logs when there is a change in Bluetooth A2DP playback state
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpPlaybackStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Current playback state
+    // Default: PLAYBACK_STATE_UNKNOWN
+    optional android.bluetooth.a2dp.PlaybackStateEnum playback_state = 2;
+    // Current audio coding mode
+    // Default: AUDIO_CODING_MODE_UNKNOWN
+    optional android.bluetooth.a2dp.AudioCodingModeEnum audio_coding_mode = 3;
+}
+
+/**
+ * Logs when there is a change in A2DP codec config for a particular remote device
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpCodecConfigChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
+    // Default SOURCE_CODEC_TYPE_INVALID
+    optional int32 codec_type = 2;
+    // Codec priroity, the higher the more preferred, -1 for disabled
+    // Default: CODEC_PRIORITY_DEFAULT
+    optional int32 codec_priority = 3;
+    // Sample rate in Hz as defined by various SAMPLE_RATE_* constants in BluetoothCodecConfig
+    // Default: SAMPLE_RATE_NONE
+    optional int32 sample_rate = 4;
+    // Bits per sample as defined by various BITS_PER_SAMPLE_* constants in BluetoothCodecConfig
+    // Default: BITS_PER_SAMPLE_NONE
+    optional int32 bits_per_sample = 5;
+    // Channel mode as defined by various CHANNEL_MODE_* constants in BluetoothCodecConfig
+    // Default: CHANNEL_MODE_NONE
+    optional int32 channel_mode = 6;
+    // Codec specific values
+    // Default 0
+    optional int64 codec_specific_1 = 7;
+    optional int64 codec_specific_2 = 8;
+    optional int64 codec_specific_3 = 9;
+    optional int64 codec_specific_4 = 10;
+}
+
+/**
+ * Logs when there is a change in selectable A2DP codec capability for a paricular remote device
+ * Each codec's capability is logged separately due to statsd restriction
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpCodecCapabilityChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
+    // Default SOURCE_CODEC_TYPE_INVALID
+    optional int32 codec_type = 2;
+    // Codec priroity, the higher the more preferred, -1 for disabled
+    // Default: CODEC_PRIORITY_DEFAULT
+    optional int32 codec_priority = 3;
+    // A bit field of supported sample rates as defined by various SAMPLE_RATE_* constants
+    // in BluetoothCodecConfig
+    // Default: empty and SAMPLE_RATE_NONE for individual item
+    optional int32 sample_rate = 4;
+    // A bit field of supported bits per sample as defined by various BITS_PER_SAMPLE_* constants
+    // in BluetoothCodecConfig
+    // Default: empty and BITS_PER_SAMPLE_NONE for individual item
+    optional int32 bits_per_sample = 5;
+    // A bit field of supported channel mode as defined by various CHANNEL_MODE_* constants in
+    // BluetoothCodecConfig
+    // Default: empty and CHANNEL_MODE_NONE for individual item
+    optional int32 channel_mode = 6;
+    // Codec specific values
+    // Default 0
+    optional int64 codec_specific_1 = 7;
+    optional int64 codec_specific_2 = 8;
+    optional int64 codec_specific_3 = 9;
+    optional int64 codec_specific_4 = 10;
+}
+
+/**
+ * Logs when A2DP failed to read from PCM source.
+ * This typically happens when audio HAL cannot supply A2DP with data fast enough for encoding.
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothA2dpAudioUnderrunReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Encoding interval in nanoseconds
+    // Default: 0
+    optional int64 encoding_interval_nanos = 2;
+    // Number of bytes of PCM data that could not be read from the source
+    // Default: 0
+    optional int32 num_missing_pcm_bytes = 3;
+}
+
+/**
+ * Logs when A2DP failed send encoded data to the remote device fast enough such that the transmit
+ * buffer queue is full and we have to drop data
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothA2dpAudioOverrunReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Encoding interval in nanoseconds
+    // Default: 0
+    optional int64 encoding_interval_nanos = 2;
+    // Number of buffers dropped in this event
+    // Each buffer is encoded in one encoding interval and consists of multiple encoded frames
+    // Default: 0
+    optional int32 num_dropped_buffers = 3;
+    // Number of encoded buffers dropped in this event
+    // Default 0
+    optional int32 num_dropped_encoded_frames = 4;
+    // Number of encoded bytes dropped in this event
+    // Default: 0
+    optional int32 num_dropped_encoded_bytes = 5;
+}
+
+/**
+ * Logs when we receive reports regarding a device's RSSI value
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceRssiReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 3;
+    // BR/EDR
+    //   Range: -128 ≤ N ≤ 127 (signed integer)
+    //   Units: dB
+    // LE:
+    //   Range: -127 to 20, 127 (signed integer)
+    //   Units: dBm
+    // Invalid when an out of range value is reported
+    optional int32 rssi = 4;
+}
+
+/**
+ * Logs when we receive reports regarding how many consecutive failed contacts for a connection
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceFailedContactCounterReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 3;
+    // Number of consecutive failed contacts for a connection corresponding to the Handle
+    // Range: uint16_t, 0-0xFFFF
+    // Default: 0xFFFFF
+    optional int32 failed_contact_counter = 4;
+}
+
+/**
+ * Logs when we receive reports regarding the tranmit power level used for a specific connection
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceTxPowerLevelReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggered by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 3;
+    // Range: -30 ≤ N ≤ 20
+    // Units: dBm
+    // Invalid when an out of range value is reported
+    optional int32 transmit_power_level = 4;
+}
+
+/**
+ * Logs when Bluetooth controller failed to reply with command status within a timeout period after
+ * receiving an HCI command from the host
+ *
+ * Logged from: system/bt
+ */
+message BluetoothHciTimeoutReported {
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_command = 1;
+}
+
+/**
+ * Logs when we receive Bluetooth Link Quality Report event from the controller
+ * See Android Bluetooth HCI specification for more details
+ *
+ * Note: all count and bytes field are counted since last event
+ *
+ * Logged from: system/bt
+ */
+message BluetoothQualityReportReported {
+    // Quality report ID
+    // Original type: uint8_t
+    // Default: BQR_ID_UNKNOWN
+    optional android.bluetooth.hci.BqrIdEnum quality_report_id = 1;
+    // Packet type of the connection
+    // Original type: uint8_t
+    // Default: BQR_PACKET_TYPE_UNKNOWN
+    optional android.bluetooth.hci.BqrPacketTypeEnum packet_types = 2;
+    // Connection handle of the connection
+    // Original type: uint16_t
+    optional int32 connection_handle = 3;
+    // Performing Role for the connection
+    // Original type: uint8_t
+    optional int32 connection_role = 4;
+    // Current Transmit Power Level for the connection. This value is the same as the controller's
+    // response to the HCI_Read_Transmit_Power_Level HCI command
+    // Original type: uint8_t
+    optional int32 tx_power_level = 5;
+    // Received Signal Strength Indication (RSSI) value for the connection. This value is an
+    // absolute receiver signal strength value
+    // Original type: int8_t
+    optional int32 rssi = 6;
+    // Signal-to-Noise Ratio (SNR) value for the connection. It is the average SNR of all the
+    // channels used by the link currently
+    // Original type: uint8_t
+    optional int32 snr = 7;
+    // Indicates the number of unused channels in AFH_channel_map
+    // Original type: uint8_t
+    optional int32 unused_afh_channel_count = 8;
+    // Indicates the number of the channels which are interfered and quality is bad but are still
+    // selected for AFH
+    // Original type: uint8_t
+    optional int32 afh_select_unideal_channel_count = 9;
+    // Current Link Supervision Timeout Setting
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint16_t
+    optional int32 lsto = 10;
+    // Piconet Clock for the specified Connection_Handle. This value is the same as the controller's
+    // response to HCI_Read_Clock HCI command with the parameter "Which_Clock" of
+    // 0x01 (Piconet Clock)
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 connection_piconet_clock = 11;
+    // The count of retransmission
+    // Original type: uint32_t
+    optional int64 retransmission_count = 12;
+    // The count of no RX
+    // Original type: uint32_t
+    optional int64 no_rx_count = 13;
+    // The count of NAK (Negative Acknowledge)
+    // Original type: uint32_t
+    optional int64 nak_count = 14;
+    // Controller timestamp of last TX ACK
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 last_tx_ack_timestamp = 15;
+    // The count of Flow-off (STOP)
+    // Original type: uint32_t
+    optional int64 flow_off_count = 16;
+    // Controller timestamp of last Flow-on (GO)
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 last_flow_on_timestamp = 17;
+    // Buffer overflow count (how many bytes of TX data are dropped) since the last event
+    // Original type: uint32_t
+    optional int64 buffer_overflow_bytes = 18;
+    // Buffer underflow count (in byte) since last event
+    // Original type: uint32_t
+    optional int64 buffer_underflow_bytes = 19;
+}
+
+/**
+ * Logs when a Bluetooth device's manufacturer information is learnt by the Bluetooth stack
+ *
+ * Notes:
+ * - Each event can be partially filled as we might learn different pieces of device
+ *   information at different time
+ * - Multiple device info events can be combined to give more complete picture
+ * - When multiple device info events tries to describe the same information, the
+ *   later one wins
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth
+ */
+message BluetoothManufacturerInfoReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Where is this device info obtained from
+    optional android.bluetooth.DeviceInfoSrcEnum source_type = 2;
+    // Name of the data source
+    // For EXTERNAL: package name of the data source
+    // For INTERNAL: null for general case, component name otherwise
+    optional string source_name = 3;
+    // Name of the manufacturer of this device
+    optional string manufacturer = 4;
+    // Model of this device
+    optional string model = 5;
+    // Hardware version of this device
+    optional string hardware_version = 6;
+    // Software version of this device
+    optional string software_version = 7;
+}
+
+/**
+ * Logs when we receive Bluetooth Read Remote Version Information Complete Event from the remote
+ * device, as documented by the Bluetooth Core HCI specification
+ * Reference: https://www.bluetooth.com/specifications/bluetooth-core-specification
+ * Vol 2, Part E, Page 1118
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothRemoteVersionInfoReported {
+    // Connection handle of the connection
+    // Original type: uint16_t
+    optional int32 connection_handle = 1;
+    // HCI command status code
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 2;
+    // 1 byte Version of current LMP in the remote controller
+    optional int32 lmp_version = 3;
+    // 2 bytes LMP manufacturer code of the remote controller
+    // https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+    optional int32 lmp_manufacturer_code = 4;
+    // 4 bytes subversion of the LMP in the remote controller
+    optional int32 lmp_subversion = 5;
+}
+
+/**
+ * Logs when certain Bluetooth SDP attributes are discovered
+ * Constant definitions are from:
+ *     https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+ *
+ * Current logged attributes:
+ * - BluetoothProfileDescriptorList
+ * - Supported Features Bitmask
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothSdpAttributeReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Short form UUIDs used to identify Bluetooth protocols, profiles, and service classes
+    // Original type: uint16_t
+    optional int32 protocol_uuid = 2;
+    // Short form UUIDs used to identify Bluetooth SDP attribute types
+    // Original type: uint16_t
+    optional int32 attribute_id = 3;
+    // Attribute value for the particular attribute
+    optional bytes attribute_value = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Logs when bond state of a Bluetooth device changes
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
+ */
+message BluetoothBondStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Preferred transport type to remote dual mode device
+    // Default: TRANSPORT_AUTO means no preference
+    optional android.bluetooth.TransportTypeEnum transport = 2;
+    // The type of this Bluetooth device (Classic, LE, or Dual mode)
+    // Default: UNKNOWN
+    optional android.bluetooth.DeviceTypeEnum type = 3;
+    // Current bond state (NONE, BONDING, BONDED)
+    // Default: BOND_STATE_UNKNOWN
+    optional android.bluetooth.BondStateEnum bond_state = 4;
+    // Bonding sub state
+    // Default: BOND_SUB_STATE_UNKNOWN
+    optional android.bluetooth.BondSubStateEnum bonding_sub_state = 5;
+    // Unbond Reason
+    // Default: UNBOND_REASON_UNKNOWN
+    optional android.bluetooth.UnbondReasonEnum unbond_reason = 6;
+}
+
+/**
+ * Logs there is an event related Bluetooth classic pairing
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothClassicPairingEventReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_cmd = 3;
+    // HCI event associated with this event
+    // Default: EVT_UNKNOWN
+    optional android.bluetooth.hci.EventEnum hci_event = 4;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 5;
+    // HCI reason code associated with this event
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum reason_code = 6;
+}
+
+/**
+ * Logs when there is an event related to Bluetooth Security Manager Protocol (SMP)
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothSmpPairingEventReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // SMP command sent or received over L2CAP
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.smp.CommandEnum smp_command = 2;
+    // Whether this command is sent or received
+    // Default: DIRECTION_UNKNOWN
+    optional android.bluetooth.DirectionEnum direction = 3;
+    // SMP failure reason code
+    // Default: PAIRING_FAIL_REASON_DEFAULT
+    optional android.bluetooth.smp.PairingFailReasonEnum smp_fail_reason = 4;
+}
 
 /**
  * Logs when something is plugged into or removed from the USB-C connector.
@@ -4699,3 +5251,24 @@
     optional float normalized_x_position = 7;
     optional float normalized_y_position = 8;
 }
+
+/**
+ * Logs that a constraint for a scheduled job has changed.
+ *
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
+ */
+message ScheduledJobConstraintChanged {
+    repeated AttributionNode attribution_node = 1;
+
+    // Name of the job.
+    optional string job_name = 2;
+
+    optional com.android.server.job.ConstraintEnum constraint = 3;
+
+    enum State {
+        UNSATISFIED = 0;
+        SATISFIED = 1;
+    }
+    optional State state = 4;
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 92f47e7..e77e212 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1808,6 +1808,29 @@
         mCalled = true;
     }
 
+    /**
+     * Called when activity gets or looses the top resumed position in the system.
+     *
+     * <p>Starting with {@link android.os.Build.VERSION_CODES#Q} multiple activities can be resumed
+     * at the same time in multi-window and multi-display modes. This callback should be used
+     * instead of {@link #onResume()} as an indication that the activity can try to open
+     * exclusive-access devices like camera.</p>
+     *
+     * <p>It will always be delivered after the activity was resumed and before it is paused. In
+     * some cases it might be skipped and activity can go straight from {@link #onResume()} to
+     * {@link #onPause()} without receiving the top resumed state.</p>
+     *
+     * @param isTopResumedActivity {@code true} if it's the topmost resumed activity in the system,
+     *                             {@code false} otherwise. A call with this as {@code true} will
+     *                             always be followed by another one with {@code false}.
+     *
+     * @see #onResume()
+     * @see #onPause()
+     * @see #onWindowFocusChanged(boolean)
+     */
+    public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
+    }
+
     void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
         if (mVoiceInteractor != null) {
             for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ee3d27c..03a09ee 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -449,6 +449,14 @@
         ViewRootImpl.ActivityConfigCallback configCallback;
         ActivityClientRecord nextIdle;
 
+        // Indicates whether this activity is currently the topmost resumed one in the system.
+        // This holds the last reported value from server.
+        boolean isTopResumedActivity;
+        // This holds the value last sent to the activity. This is needed, because an update from
+        // server may come at random time, but we always need to report changes between ON_RESUME
+        // and ON_PAUSE to the app.
+        boolean lastReportedTopResumedState;
+
         ProfilerInfo profilerInfo;
 
         @UnsupportedAppUsage
@@ -3295,16 +3303,14 @@
         final boolean resumed = !r.paused;
         if (resumed) {
             r.activity.mTemporaryPause = true;
-            mInstrumentation.callActivityOnPause(r.activity);
+            performPauseActivityIfNeeded(r, "performNewIntents");
         }
         checkAndBlockForNetworkAccess();
         deliverNewIntents(r, intents);
         if (resumed) {
-            r.activity.performResume(false, "performNewIntents");
+            performResumeActivity(token, false, "performNewIntents");
             r.activity.mTemporaryPause = false;
-        }
-
-        if (r.paused && andPause) {
+        } else if (andPause) {
             // In this case the activity was in the paused state when we delivered the intent,
             // to guarantee onResume gets called after onNewIntent we temporarily resume the
             // activity and pause again as the caller wanted.
@@ -3957,6 +3963,8 @@
             r.state = null;
             r.persistentState = null;
             r.setState(ON_RESUME);
+
+            reportTopResumedActivityChanged(r, r.isTopResumedActivity);
         } catch (Exception e) {
             if (!mInstrumentation.onException(r.activity, e)) {
                 throw new RuntimeException("Unable to resume activity "
@@ -4111,6 +4119,45 @@
         Looper.myQueue().addIdleHandler(new Idler());
     }
 
+
+    @Override
+    public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r == null || r.activity == null) {
+            Slog.w(TAG, "Not found target activity to report position change for token: " + token);
+            return;
+        }
+
+        if (DEBUG_ORDER) {
+            Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r);
+        }
+
+        if (r.isTopResumedActivity == onTop) {
+            throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
+        }
+
+        r.isTopResumedActivity = onTop;
+
+        if (r.getLifecycleState() == ON_RESUME) {
+            reportTopResumedActivityChanged(r, onTop);
+        } else {
+            if (DEBUG_ORDER) {
+                Slog.d(TAG, "Won't deliver top position change in state=" + r.getLifecycleState());
+            }
+        }
+    }
+
+    /**
+     * Call {@link Activity#onTopResumedActivityChanged(boolean)} if its top resumed state changed
+     * since the last report.
+     */
+    private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop) {
+        if (r.lastReportedTopResumedState != onTop) {
+            r.lastReportedTopResumedState = onTop;
+            r.activity.onTopResumedActivityChanged(onTop);
+        }
+    }
+
     @Override
     public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
             int configChanges, PendingTransactionActions pendingActions, String reason) {
@@ -4202,6 +4249,10 @@
             return;
         }
 
+        // Always reporting top resumed position loss when pausing an activity. If necessary, it
+        // will be restored in performResumeActivity().
+        reportTopResumedActivityChanged(r, false /* onTop */);
+
         try {
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 07dbb6b..70badfa 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -105,6 +105,16 @@
             boolean isForward, String reason);
 
     /**
+     * Notify the activity about top resumed state change.
+     * @param token Target activity token.
+     * @param isTopResumedActivity Current state of the activity, {@code true} if it's the
+     *                             topmost resumed activity in the system, {@code false} otherwise.
+     * @param reason Reason for performing this operation.
+     */
+    public abstract void handleTopResumedActivityChanged(IBinder token,
+            boolean isTopResumedActivity, String reason);
+
+    /**
      * Stop the activity.
      * @param token Target activity token.
      * @param show Flag indicating whether activity is still shown.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fb65da1..412d7f4 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -277,6 +277,7 @@
     void unstableProviderDied(in IBinder connection);
     boolean isIntentSenderAnActivity(in IIntentSender sender);
     boolean isIntentSenderAForegroundService(in IIntentSender sender);
+    boolean isIntentSenderABroadcast(in IIntentSender sender);
     int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
             in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
             int requestCode, int flags, in ProfilerInfo profilerInfo,
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 75d95b2..55014eb 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1113,6 +1113,19 @@
 
     /**
      * @hide
+     * Check whether this PendingIntent will launch an Activity.
+     */
+    public boolean isBroadcast() {
+        try {
+            return ActivityManager.getService()
+                .isIntentSenderABroadcast(mTarget);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
      * Return the Intent of this PendingIntent.
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
new file mode 100644
index 0000000..4064a02
--- /dev/null
+++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2019 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.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+/**
+ * Top resumed activity changed callback.
+ * @hide
+ */
+public class TopResumedActivityChangeItem extends ClientTransactionItem {
+
+    private boolean mOnTop;
+
+    @Override
+    public void execute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem");
+        client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem");
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+
+    // ObjectPoolItem implementation
+
+    private TopResumedActivityChangeItem() {}
+
+    /** Obtain an instance initialized with provided params. */
+    public static TopResumedActivityChangeItem obtain(boolean onTop) {
+        TopResumedActivityChangeItem instance =
+                ObjectPool.obtain(TopResumedActivityChangeItem.class);
+        if (instance == null) {
+            instance = new TopResumedActivityChangeItem();
+        }
+        instance.mOnTop = onTop;
+
+        return instance;
+    }
+
+    @Override
+    public void recycle() {
+        mOnTop = false;
+        ObjectPool.recycle(this);
+    }
+
+
+    // Parcelable implementation
+
+    /** Write to Parcel. */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBoolean(mOnTop);
+    }
+
+    /** Read from Parcel. */
+    private TopResumedActivityChangeItem(Parcel in) {
+        mOnTop = in.readBoolean();
+    }
+
+    public static final Creator<TopResumedActivityChangeItem> CREATOR =
+            new Creator<TopResumedActivityChangeItem>() {
+                public TopResumedActivityChangeItem createFromParcel(Parcel in) {
+                    return new TopResumedActivityChangeItem(in);
+                }
+
+                public TopResumedActivityChangeItem[] newArray(int size) {
+                    return new TopResumedActivityChangeItem[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final TopResumedActivityChangeItem other = (TopResumedActivityChangeItem) o;
+        return mOnTop == other.mOnTop;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + (mOnTop ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "TopResumedActivityChangeItem{onTop=" + mOnTop + "}";
+    }
+}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 3d3c03a..43ce521 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -287,19 +287,14 @@
 
     /** A class which is used to share the usage limit data for an app or a group of apps. */
     public static class AppUsageLimitData {
-        private final boolean mGroupLimit;
         private final long mTotalUsageLimit;
         private final long mUsageRemaining;
 
-        public AppUsageLimitData(boolean groupLimit, long totalUsageLimit, long usageRemaining) {
-            this.mGroupLimit = groupLimit;
+        public AppUsageLimitData(long totalUsageLimit, long usageRemaining) {
             this.mTotalUsageLimit = totalUsageLimit;
             this.mUsageRemaining = usageRemaining;
         }
 
-        public boolean isGroupLimit() {
-            return mGroupLimit;
-        }
         public long getTotalUsageLimit() {
             return mTotalUsageLimit;
         }
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index b7366f1..e897b91 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -18,7 +18,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -77,18 +76,6 @@
     }
 
     /**
-     * @deprecated use {@link #startActivity(ComponentName, UserHandle)} instead.
-     *
-     * @removed
-     * @hide
-     */
-    @Deprecated
-    @UnsupportedAppUsage
-    public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
-        startActivity(component, targetUser);
-    }
-
-    /**
      * Starts the specified activity of the caller package in the specified profile. Unlike
      * {@link #startMainActivity}, this can start any activity of the caller package, not just
      * the main activity.
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 89630e1..36bb5d4 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1658,35 +1658,23 @@
      * A class that encapsulates information about the usage limit set for an app or
      * a group of apps.
      *
-     * <p>The launcher can query specifics about the usage limit such as if it is a group limit,
-     * how much usage time the limit has, and how much of the total usage time is remaining
-     * via the APIs available in this class.
+     * <p>The launcher can query specifics about the usage limit such as how much usage time
+     * the limit has and how much of the total usage time is remaining via the APIs available
+     * in this class.
      *
      * @see #getAppUsageLimit(String, UserHandle)
      */
     public static final class AppUsageLimit implements Parcelable {
-        private final boolean mGroupLimit;
         private final long mTotalUsageLimit;
         private final long mUsageRemaining;
 
         /** @hide */
-        public AppUsageLimit(boolean groupLimit, long totalUsageLimit, long usageRemaining) {
-            this.mGroupLimit = groupLimit;
+        public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
             this.mTotalUsageLimit = totalUsageLimit;
             this.mUsageRemaining = usageRemaining;
         }
 
         /**
-         * Returns whether this limit refers to a group of apps.
-         *
-         * @return {@code TRUE} if the limit refers to a group of apps, {@code FALSE} otherwise.
-         * @hide
-         */
-        public boolean isGroupLimit() {
-            return mGroupLimit;
-        }
-
-        /**
          * Returns the total usage limit in milliseconds set for an app or a group of apps.
          *
          * @return the total usage limit in milliseconds
@@ -1706,7 +1694,6 @@
         }
 
         private AppUsageLimit(Parcel source) {
-            mGroupLimit = source.readBoolean();
             mTotalUsageLimit = source.readLong();
             mUsageRemaining = source.readLong();
         }
@@ -1730,7 +1717,6 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeBoolean(mGroupLimit);
             dest.writeLong(mTotalUsageLimit);
             dest.writeLong(mUsageRemaining);
         }
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index d2c0e7b..5d4928c 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -182,6 +182,38 @@
     }
 
     /**
+     * Queries whether the given buffer description is supported by the system. If this returns
+     * true, then the allocation may succeed until resource exhaustion occurs. If this returns
+     * false then this combination will never succeed.
+     *
+     * @param width The width in pixels of the buffer
+     * @param height The height in pixels of the buffer
+     * @param format The @Format of each pixel
+     * @param layers The number of layers in the buffer
+     * @param usage The @Usage flags describing how the buffer will be used
+     * @return True if the combination is supported, false otherwise.
+     */
+    public static boolean isSupported(int width, int height, @Format int format, int layers,
+            @Usage long usage) {
+        if (!HardwareBuffer.isSupportedFormat(format)) {
+            throw new IllegalArgumentException("Invalid pixel format " + format);
+        }
+        if (width <= 0) {
+            throw new IllegalArgumentException("Invalid width " + width);
+        }
+        if (height <= 0) {
+            throw new IllegalArgumentException("Invalid height " + height);
+        }
+        if (layers <= 0) {
+            throw new IllegalArgumentException("Invalid layer count " + layers);
+        }
+        if (format == BLOB && height != 1) {
+            throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
+        }
+        return nIsSupported(width, height, format, layers, usage);
+    }
+
+    /**
      * Private use only. See {@link #create(int, int, int, int, long)}. May also be
      * called from JNI using an already allocated native <code>HardwareBuffer</code>.
      */
@@ -386,4 +418,6 @@
     private static native int nGetLayers(long nativeObject);
     @FastNative
     private static native long nGetUsage(long nativeObject);
+    private static native boolean nIsSupported(int width, int height, int format, int layers,
+            long usage);
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 9758308..425b956 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3721,6 +3721,59 @@
             new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
 
     /**
+     * <p>The available dynamic depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>These are output stream configurations for use with
+     * dataSpace DYNAMIC_DEPTH. The configurations are
+     * listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>Only devices that support depth output for at least
+     * the HAL_PIXEL_FORMAT_Y16 dense depth map along with
+     * HAL_PIXEL_FORMAT_BLOB with the same size or size with
+     * the same aspect ratio can have dynamic depth dataspace
+     * stream configuration. {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} also
+     * needs to be set to FALSE.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfiguration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.depth.availableDynamicDepthStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for dynamic depth output streams.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDynamicDepthMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for dynamic depth streams.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>All dynamic depth output streams may have a nonzero stall
+     * duration.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDynamicDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
      * <p>String containing the ids of the underlying physical cameras.</p>
      * <p>For a logical camera, this is concatenation of all underlying physical camera IDs.
      * The null terminator for physical camera ID must be preserved so that the whole string
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c527ab4..7877a4d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1119,6 +1119,8 @@
                 continue;
             }
 
+            // Dynamic depth streams involve alot of SW processing and currently cannot be
+            // recommended.
             StreamConfigurationMap map = null;
             switch (i) {
                 case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
@@ -1127,28 +1129,44 @@
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             /*depthconfiguration*/ null, /*depthminduration*/ null,
-                            /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null,
+                            /*depthstallduration*/ null,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highspeedvideoconfigurations*/ null,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
                 case RecommendedStreamConfigurationMap.USECASE_RECORD:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             /*depthconfiguration*/ null, /*depthminduration*/ null,
-                            /*depthstallduration*/ null, highSpeedVideoConfigurations,
+                            /*depthstallduration*/ null,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            highSpeedVideoConfigurations,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
                 case RecommendedStreamConfigurationMap.USECASE_ZSL:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             depthScData.streamConfigurationArray, depthScData.minDurationArray,
-                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            depthScData.stallDurationArray,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highSpeedVideoConfigurations*/ null,
                             inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
                     break;
                 default:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             depthScData.streamConfigurationArray, depthScData.minDurationArray,
-                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            depthScData.stallDurationArray,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highSpeedVideoConfigurations*/ null,
                             /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
             }
 
@@ -1206,6 +1224,12 @@
                 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
         StreamConfigurationDuration[] depthStallDurations = getBase(
                 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+        StreamConfiguration[] dynamicDepthConfigurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+        StreamConfigurationDuration[] dynamicDepthMinFrameDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
+        StreamConfigurationDuration[] dynamicDepthStallDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
         HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
         ReprocessFormatsMap inputOutputFormatsMap = getBase(
@@ -1214,7 +1238,8 @@
         return new StreamConfigurationMap(
                 configurations, minFrameDurations, stallDurations,
                 depthConfigurations, depthMinFrameDurations, depthStallDurations,
-                highSpeedVideoConfigurations, inputOutputFormatsMap,
+                dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
+                dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
                 listHighResolution);
     }
 
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index dd052a8..a22e008 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -95,13 +95,17 @@
             StreamConfiguration[] depthConfigurations,
             StreamConfigurationDuration[] depthMinFrameDurations,
             StreamConfigurationDuration[] depthStallDurations,
+            StreamConfiguration[] dynamicDepthConfigurations,
+            StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
+            StreamConfigurationDuration[] dynamicDepthStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution) {
         this(configurations, minFrameDurations, stallDurations,
                     depthConfigurations, depthMinFrameDurations, depthStallDurations,
-                    highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
-                    /*enforceImplementationDefined*/ true);
+                    dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
+                    dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
+                    listHighResolution, /*enforceImplementationDefined*/ true);
     }
 
     /**
@@ -131,6 +135,9 @@
             StreamConfiguration[] depthConfigurations,
             StreamConfigurationDuration[] depthMinFrameDurations,
             StreamConfigurationDuration[] depthStallDurations,
+            StreamConfiguration[] dynamicDepthConfigurations,
+            StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
+            StreamConfigurationDuration[] dynamicDepthStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution,
@@ -163,6 +170,19 @@
                     "depthStallDurations");
         }
 
+        if (dynamicDepthConfigurations == null) {
+            mDynamicDepthConfigurations = new StreamConfiguration[0];
+            mDynamicDepthMinFrameDurations = new StreamConfigurationDuration[0];
+            mDynamicDepthStallDurations = new StreamConfigurationDuration[0];
+        } else {
+            mDynamicDepthConfigurations = checkArrayElementsNotNull(dynamicDepthConfigurations,
+                    "dynamicDepthConfigurations");
+            mDynamicDepthMinFrameDurations = checkArrayElementsNotNull(
+                    dynamicDepthMinFrameDurations, "dynamicDepthMinFrameDurations");
+            mDynamicDepthStallDurations = checkArrayElementsNotNull(dynamicDepthStallDurations,
+                    "dynamicDepthStallDurations");
+        }
+
         if (highSpeedVideoConfigurations == null) {
             mHighSpeedVideoConfigurations = new HighSpeedVideoConfiguration[0];
         } else {
@@ -205,6 +225,15 @@
             mDepthOutputFormats.put(config.getFormat(),
                     mDepthOutputFormats.get(config.getFormat()) + 1);
         }
+        for (StreamConfiguration config : mDynamicDepthConfigurations) {
+            if (!config.isOutput()) {
+                // Ignoring input configs
+                continue;
+            }
+
+            mDynamicDepthOutputFormats.put(config.getFormat(),
+                    mDynamicDepthOutputFormats.get(config.getFormat()) + 1);
+        }
 
         if (configurations != null && enforceImplementationDefined &&
                 mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
@@ -335,6 +364,8 @@
         int dataspace = imageFormatToDataspace(format);
         if (dataspace == HAL_DATASPACE_DEPTH) {
             return mDepthOutputFormats.indexOfKey(internalFormat) >= 0;
+        } else if (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
+            return mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0;
         } else {
             return getFormatsMap(/*output*/true).indexOfKey(internalFormat) >= 0;
         }
@@ -446,7 +477,9 @@
         boolean isFlexible = SurfaceUtils.isFlexibleConsumer(surface);
 
         StreamConfiguration[] configs =
-                surfaceDataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+                surfaceDataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
+                surfaceDataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+                mConfigurations;
         for (StreamConfiguration config : configs) {
             if (config.getFormat() == surfaceFormat && config.isOutput()) {
                 // Matching format, either need exact size match, or a flexible consumer
@@ -479,7 +512,9 @@
         int dataspace = imageFormatToDataspace(format);
 
         StreamConfiguration[] configs =
-            dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+            dataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
+            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+            mConfigurations;
         for (StreamConfiguration config : configs) {
             if ((config.getFormat() == internalFormat) && config.isOutput() &&
                     config.getSize().equals(size)) {
@@ -992,6 +1027,12 @@
                     Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
                     Arrays.equals(mStallDurations, other.mStallDurations) &&
                     Arrays.equals(mDepthConfigurations, other.mDepthConfigurations) &&
+                    Arrays.equals(mDepthMinFrameDurations, other.mDepthMinFrameDurations) &&
+                    Arrays.equals(mDepthStallDurations, other.mDepthStallDurations) &&
+                    Arrays.equals(mDynamicDepthConfigurations, other.mDynamicDepthConfigurations) &&
+                    Arrays.equals(mDynamicDepthMinFrameDurations,
+                            other.mDynamicDepthMinFrameDurations) &&
+                    Arrays.equals(mDynamicDepthStallDurations, other.mDynamicDepthStallDurations) &&
                     Arrays.equals(mHighSpeedVideoConfigurations,
                             other.mHighSpeedVideoConfigurations);
         }
@@ -1005,9 +1046,10 @@
     public int hashCode() {
         // XX: do we care about order?
         return HashCodeHelpers.hashCodeGeneric(
-                mConfigurations, mMinFrameDurations,
-                mStallDurations,
-                mDepthConfigurations, mHighSpeedVideoConfigurations);
+                mConfigurations, mMinFrameDurations, mStallDurations,
+                mDepthConfigurations, mDepthMinFrameDurations, mDepthStallDurations,
+                mDynamicDepthConfigurations, mDynamicDepthMinFrameDurations,
+                mDynamicDepthStallDurations, mHighSpeedVideoConfigurations);
     }
 
     // Check that the argument is supported by #getOutputFormats or #getInputFormats
@@ -1022,6 +1064,10 @@
                 if (mDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
                 }
+            } else if (internalDataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
+                if (mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
+                    return format;
+                }
             } else {
                 if (mAllOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
@@ -1245,6 +1291,7 @@
         switch (format) {
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 return HAL_PIXEL_FORMAT_BLOB;
             case ImageFormat.DEPTH16:
                 return HAL_PIXEL_FORMAT_Y16;
@@ -1264,6 +1311,7 @@
      * <li>ImageFormat.JPEG => HAL_DATASPACE_V0_JFIF
      * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
      * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
+     * <li>ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH
      * <li>others => HAL_DATASPACE_UNKNOWN
      * </ul>
      * </p>
@@ -1293,6 +1341,8 @@
             case ImageFormat.DEPTH16:
             case ImageFormat.RAW_DEPTH:
                 return HAL_DATASPACE_DEPTH;
+            case ImageFormat.DEPTH_JPEG:
+                return HAL_DATASPACE_DYNAMIC_DEPTH;
             default:
                 return HAL_DATASPACE_UNKNOWN;
         }
@@ -1343,12 +1393,16 @@
         SparseIntArray formatsMap =
                 !output ? mInputFormats :
                 dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
+                dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthOutputFormats :
                 highRes ? mHighResOutputFormats :
                 mOutputFormats;
 
         int sizesCount = formatsMap.get(format);
-        if ( ((!output || dataspace == HAL_DATASPACE_DEPTH) && sizesCount == 0) ||
-                (output && dataspace != HAL_DATASPACE_DEPTH && mAllOutputFormats.get(format) == 0)) {
+        if ( ((!output || (dataspace == HAL_DATASPACE_DEPTH ||
+                            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) && sizesCount == 0) ||
+                (output && (dataspace != HAL_DATASPACE_DEPTH &&
+                            dataspace != HAL_DATASPACE_DYNAMIC_DEPTH) &&
+                 mAllOutputFormats.get(format) == 0)) {
             // Only throw if this is really not supported at all
             throw new IllegalArgumentException("format not available");
         }
@@ -1357,9 +1411,13 @@
         int sizeIndex = 0;
 
         StreamConfiguration[] configurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                mConfigurations;
         StreamConfigurationDuration[] minFrameDurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : mMinFrameDurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations :
+                mMinFrameDurations;
 
         for (StreamConfiguration config : configurations) {
             int fmt = config.getFormat();
@@ -1386,7 +1444,21 @@
             }
         }
 
-        if (sizeIndex != sizesCount) {
+        // Dynamic depth streams can have both fast and also high res modes.
+        if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) {
+
+            if (sizeIndex > sizesCount) {
+                throw new AssertionError(
+                        "Too many dynamic depth sizes (expected " + sizesCount + ", actual " +
+                        sizeIndex + ")");
+            }
+
+            if (sizeIndex <= 0) {
+                sizes = new Size[0];
+            } else {
+                sizes = Arrays.copyOf(sizes, sizeIndex);
+            }
+        } else if (sizeIndex != sizesCount) {
             throw new AssertionError(
                     "Too few sizes (expected " + sizesCount + ", actual " + sizeIndex + ")");
         }
@@ -1409,6 +1481,10 @@
             for (int j = 0; j < mDepthOutputFormats.size(); j++) {
                 formats[i++] = depthFormatToPublic(mDepthOutputFormats.keyAt(j));
             }
+            if (mDynamicDepthOutputFormats.size() > 0) {
+                // Only one publicly dynamic depth format is available.
+                formats[i++] = ImageFormat.DEPTH_JPEG;
+            }
         }
         if (formats.length != i) {
             throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
@@ -1451,11 +1527,13 @@
     private StreamConfigurationDuration[] getDurations(int duration, int dataspace) {
         switch (duration) {
             case DURATION_MIN_FRAME:
-                return (dataspace == HAL_DATASPACE_DEPTH) ?
-                        mDepthMinFrameDurations : mMinFrameDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
+                        (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ?
+                        mDynamicDepthMinFrameDurations : mMinFrameDurations;
             case DURATION_STALL:
-                return (dataspace == HAL_DATASPACE_DEPTH) ?
-                        mDepthStallDurations : mStallDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthStallDurations :
+                        (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthStallDurations :
+                        mStallDurations;
             default:
                 throw new IllegalArgumentException("duration was invalid");
         }
@@ -1467,6 +1545,7 @@
         int size = formatsMap.size();
         if (output) {
             size += mDepthOutputFormats.size();
+            size += mDynamicDepthOutputFormats.size();
         }
 
         return size;
@@ -1486,10 +1565,11 @@
         return false;
     }
 
-    private boolean isSupportedInternalConfiguration(int format, int dataspace,
-            Size size) {
+    private boolean isSupportedInternalConfiguration(int format, int dataspace, Size size) {
         StreamConfiguration[] configurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                mConfigurations;
 
         for (int i = 0; i < configurations.length; i++) {
             if (configurations[i].getFormat() == format &&
@@ -1681,6 +1761,8 @@
                 return "DEPTH16";
             case ImageFormat.DEPTH_POINT_CLOUD:
                 return "DEPTH_POINT_CLOUD";
+            case ImageFormat.DEPTH_JPEG:
+                return "DEPTH_JPEG";
             case ImageFormat.RAW_DEPTH:
                 return "RAW_DEPTH";
             case ImageFormat.PRIVATE:
@@ -1712,6 +1794,7 @@
             (1 << HAL_DATASPACE_RANGE_SHIFT);
 
     private static final int HAL_DATASPACE_DEPTH = 0x1000;
+    private static final int HAL_DATASPACE_DYNAMIC_DEPTH = 0x1002;
 
     private static final long DURATION_20FPS_NS = 50000000L;
     /**
@@ -1728,6 +1811,10 @@
     private final StreamConfigurationDuration[] mDepthMinFrameDurations;
     private final StreamConfigurationDuration[] mDepthStallDurations;
 
+    private final StreamConfiguration[] mDynamicDepthConfigurations;
+    private final StreamConfigurationDuration[] mDynamicDepthMinFrameDurations;
+    private final StreamConfigurationDuration[] mDynamicDepthStallDurations;
+
     private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
     private final ReprocessFormatsMap mInputOutputFormatsMap;
 
@@ -1745,6 +1832,8 @@
     private final SparseIntArray mInputFormats = new SparseIntArray();
     /** internal format -> num depth output sizes mapping, for HAL_DATASPACE_DEPTH */
     private final SparseIntArray mDepthOutputFormats = new SparseIntArray();
+    /** internal format -> num dynamic depth output sizes mapping, for HAL_DATASPACE_DYNAMIC_DEPTH */
+    private final SparseIntArray mDynamicDepthOutputFormats = new SparseIntArray();
     /** High speed video Size -> FPS range count mapping*/
     private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
             new HashMap<Size, Integer>();
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 148dd91..d58e00a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -112,14 +112,12 @@
     @SystemApi
     public interface IntelligenceAttention {
         String NAMESPACE = "intelligence_attention";
-        /**
-         * If {@code true}, enables the attention check.
-         */
-        String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
-        /**
-         * Settings for performing the attention check.
-         */
-        String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+
+        /** If {@code true}, enables the attention features. */
+        String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
+
+        /** Settings for the attention features. */
+        String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
     }
 
     /**
@@ -182,6 +180,22 @@
     }
 
     /**
+     * Namespace for {@link AttentionManagerService} related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface AttentionManagerService {
+        String NAMESPACE = "attention_manager_service";
+
+        /** If {@code true}, enables {@link AttentionManagerService} features. */
+        String PROPERTY_SERVICE_ENABLED = "service_enabled";
+
+        /** Allows a CTS to inject a fake implementation. */
+        String PROPERTY_COMPONENT_NAME = "component_name";
+    }
+
+    /**
      * Namespace for storage-related features.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f04c752..927c729 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11799,6 +11799,44 @@
         public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";
 
         /**
+         * Broadcast dispatch tuning parameters specific to foreground broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true"
+         *
+         * The following keys are supported:
+         * <pre>
+         * bcast_timeout                (long)
+         * bcast_slow_time              (long)
+         * bcast_deferral               (long)
+         * bcast_deferral_decay_factor  (float)
+         * bcast_deferral_floor         (long)
+         * </pre>
+         *
+         * @hide
+         */
+        public static final String BROADCAST_FG_CONSTANTS = "bcast_fg_constants";
+
+        /**
+         * Broadcast dispatch tuning parameters specific to background broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true".
+         * See {@link #BROADCAST_FG_CONSTANTS} for the list of supported keys.
+         *
+         * @hide
+         */
+        public static final String BROADCAST_BG_CONSTANTS = "bcast_bg_constants";
+
+        /**
+         * Broadcast dispatch tuning parameters specific to specific "offline" broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true".
+         * See {@link #BROADCAST_FG_CONSTANTS} for the list of supported keys.
+         *
+         * @hide
+         */
+        public static final String BROADCAST_OFFLOAD_CONSTANTS = "bcast_offload_constants";
+
+        /**
          * Whether or not App Standby feature is enabled by system. This controls throttling of apps
          * based on usage patterns and predictions. Platform will turn on this feature if both this
          * flag and {@link #ADAPTIVE_BATTERY_MANAGEMENT_ENABLED} is on.
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index b9017b3..d7f1b9f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -156,8 +156,7 @@
         // Wait for system server to return the component name.
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         mHandler.sendMessage(obtainMessage(
-                ContentCaptureManager::handleReceiverServiceComponentName,
-                this, mContext.getUserId(), resultReceiver));
+                ContentCaptureManager::handleGetComponentName, this, resultReceiver));
 
         try {
             return resultReceiver.getParcelableResult();
@@ -198,7 +197,7 @@
         Preconditions.checkNotNull(request);
 
         try {
-            mService.removeUserData(mContext.getUserId(), request);
+            mService.removeUserData(request);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -227,9 +226,9 @@
 
 
     /** Retrieves the component name of the target content capture service through system_server. */
-    private void handleReceiverServiceComponentName(int userId, IResultReceiver resultReceiver) {
+    private void handleGetComponentName(@NonNull IResultReceiver resultReceiver) {
         try {
-            mService.getReceiverServiceComponentName(userId, resultReceiver);
+            mService.getServiceComponentName(resultReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Unable to retrieve service component name: " + e);
         }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 51aea16..56ed8bf 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -34,21 +34,21 @@
   */
 oneway interface IContentCaptureManager {
     /**
-     * Starts a new session for the provided {@code userId} running as part of the
+     * Starts a new session for the calling user running as part of the
      * app's activity identified by {@code activityToken}/{@code componentName}.
      *
      * @param sessionId Unique session id as provided by the app.
      * @param flags Meta flags that enable or disable content capture (see
      *     {@link IContentCaptureContext#flags}).
      */
-    void startSession(int userId, IBinder activityToken, in ComponentName componentName,
+    void startSession(IBinder activityToken, in ComponentName componentName,
                       String sessionId, int flags, in IResultReceiver result);
 
     /**
-     * Marks the end of a session for the provided {@code userId} identified by
+     * Marks the end of a session for the calling user identified by
      * the corresponding {@code startSession}'s {@code sessionId}.
      */
-    void finishSession(int userId, String sessionId);
+    void finishSession(String sessionId);
 
     /**
      * Returns the content capture service's component name (if enabled and
@@ -56,10 +56,10 @@
      * @param Receiver of the content capture service's @{code ComponentName}
      *     provided {@code Bundle} with key "{@code EXTRA}".
      */
-    void getReceiverServiceComponentName(int userId, in IResultReceiver result);
+    void getServiceComponentName(in IResultReceiver result);
 
     /**
-     * Requests the removal of user data for the provided {@code userId}.
+     * Requests the removal of user data for the calling user.
      */
-    void removeUserData(int userId, in UserDataRemovalRequest request);
+    void removeUserData(in UserDataRemovalRequest request);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 9e99c88..83dbf2d 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -211,8 +211,8 @@
         try {
             if (mSystemServerInterface == null) return;
 
-            mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
-                    componentName, mId, flags, new IResultReceiver.Stub() {
+            mSystemServerInterface.startSession(mApplicationToken, componentName, mId, flags,
+                    new IResultReceiver.Stub() {
                         @Override
                         public void send(int resultCode, Bundle resultData) {
                             IBinder binder = null;
@@ -473,7 +473,7 @@
         try {
             if (mSystemServerInterface == null) return;
 
-            mSystemServerInterface.finishSession(mContext.getUserId(), mId);
+            mSystemServerInterface.finishSession(mId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error destroying system-service session " + mId + " for "
                     + getDebugState() + ": " + e);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 803462d..299801a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -22,6 +22,8 @@
 import android.app.prediction.AppPredictionManager;
 import android.app.prediction.AppPredictor;
 import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -111,6 +113,7 @@
     private static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = false;
     // TODO(b/123088566) Share these in a better way.
     private static final String APP_PREDICTION_SHARE_UI_SURFACE = "share";
+    public static final String LAUNCH_LOCATON_DIRECT_SHARE = "direct_share";
     private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
     public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
     private AppPredictor mAppPredictor;
@@ -787,9 +790,11 @@
         // Do nothing. We'll send the voice stuff ourselves.
     }
 
-    // TODO(b/123377860) Send clicked ShortcutInfo to mAppPredictor
     void updateModelAndChooserCounts(TargetInfo info) {
         if (info != null) {
+            if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
+                sendClickToAppPredictor(info);
+            }
             final ResolveInfo ri = info.getResolveInfo();
             Intent targetIntent = getTargetIntent();
             if (ri != null && ri.activityInfo != null && targetIntent != null) {
@@ -802,13 +807,39 @@
                     Log.d(TAG, "ResolveInfo Package is " + ri.activityInfo.packageName);
                     Log.d(TAG, "Action to be updated is " + targetIntent.getAction());
                 }
-            } else if(DEBUG) {
+            } else if (DEBUG) {
                 Log.d(TAG, "Can not log Chooser Counts of null ResovleInfo");
             }
         }
         mIsSuccessfullySelected = true;
     }
 
+    private void sendClickToAppPredictor(TargetInfo targetInfo) {
+        if (!(targetInfo instanceof ChooserTargetInfo)) {
+            return;
+        }
+        ChooserTarget chooserTarget = ((ChooserTargetInfo) targetInfo).getChooserTarget();
+        ComponentName componentName = chooserTarget.getComponentName();
+        Bundle extras = chooserTarget.getIntentExtras();
+        if (extras == null) {
+            return;
+        }
+        String shortcutId = extras.getString(Intent.EXTRA_SHORTCUT_ID);
+        if (shortcutId == null) {
+            return;
+        }
+        mAppPredictor.notifyAppTargetEvent(
+                new AppTargetEvent.Builder(
+                    new AppTarget(
+                        new AppTargetId(shortcutId),
+                        componentName.getPackageName(),
+                        componentName.getClassName(),
+                        getUser()),
+                    AppTargetEvent.ACTION_LAUNCH
+                ).setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE)
+                .build());
+    }
+
     void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
         if (mRefinementResultReceiver != null) {
             mRefinementResultReceiver.destroy();
@@ -1128,6 +1159,10 @@
             return mBadgeContentDescription;
         }
 
+        public ChooserTarget getChooserTarget() {
+            return mChooserTarget;
+        }
+
         @Override
         public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
             return new ChooserTargetInfo(this, fillInIntent, flags);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 0466aaa..9afd5d0 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -166,6 +166,7 @@
         "android_media_AudioRecord.cpp",
         "android_media_AudioSystem.cpp",
         "android_media_AudioTrack.cpp",
+        "android_media_AudioAttributes.cpp",
         "android_media_DeviceCallback.cpp",
         "android_media_JetPlayer.cpp",
         "android_media_MediaMetricsJNI.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f458299..c90071a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -107,6 +107,7 @@
 extern int register_android_media_AudioRecord(JNIEnv *env);
 extern int register_android_media_AudioSystem(JNIEnv *env);
 extern int register_android_media_AudioTrack(JNIEnv *env);
+extern int register_android_media_AudioAttributes(JNIEnv *env);
 extern int register_android_media_MicrophoneInfo(JNIEnv *env);
 extern int register_android_media_JetPlayer(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
@@ -1470,6 +1471,7 @@
     REG_JNI(register_android_media_AudioSystem),
     REG_JNI(register_android_media_AudioRecord),
     REG_JNI(register_android_media_AudioTrack),
+    REG_JNI(register_android_media_AudioAttributes),
     REG_JNI(register_android_media_JetPlayer),
     REG_JNI(register_android_media_MicrophoneInfo),
     REG_JNI(register_android_media_RemoteDisplay),
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 8174a41..2d1fec8 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -104,6 +104,21 @@
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
 }
 
+static jboolean android_hardware_HardwareBuffer_isSupported(JNIEnv* env, jobject clazz,
+        jint width, jint height, jint format, jint layers, jlong usage) {
+
+    AHardwareBuffer_Desc desc;
+    desc.width = width;
+    desc.height = height;
+    desc.format = format;
+    desc.layers = layers;
+    desc.usage = usage;
+    desc.stride = 0;
+    desc.rfu0 = 0;
+    desc.rfu1 = 0;
+    return AHardwareBuffer_isSupported(&desc);
+}
+
 //----------------------------------------------------------------------------
 // Accessors
 // ----------------------------------------------------------------------------
@@ -234,6 +249,8 @@
             (void*) android_hardware_HardwareBuffer_write },
     { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
             (void*) android_hardware_HardwareBuffer_read },
+    { "nIsSupported",  "(IIIIJ)Z",
+            (void*) android_hardware_HardwareBuffer_isSupported },
 
     // --------------- @FastNative ----------------------
     { "nGetWidth", "(J)I",      (void*) android_hardware_HardwareBuffer_getWidth },
diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp
new file mode 100644
index 0000000..bfe6162
--- /dev/null
+++ b/core/jni/android_media_AudioAttributes.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioAttributes-JNI"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+
+#include <utils/Log.h>
+#include <vector>
+
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include "android_media_AudioAttributes.h"
+#include "android_media_AudioErrors.h"
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioAttributes";
+
+static jclass gAudioAttributesClass;
+static struct {
+    jfieldID    mUsage;         // AudioAttributes.mUsage
+    jfieldID    mSource;        // AudioAttributes.mSource
+    jfieldID    mContentType;   // AudioAttributes.mContentType
+    jfieldID    mFlags;         // AudioAttributes.mFlags
+    jfieldID    mFormattedTags; // AudioAttributes.mFormattedTags
+} gAudioAttributesFields;
+
+static jclass gAudioAttributesBuilderClass;
+static jmethodID gAudioAttributesBuilderCstor;
+static struct {
+    jmethodID build;
+    jmethodID setUsage;
+    jmethodID setInternalCapturePreset;
+    jmethodID setContentType;
+    jmethodID setFlags;
+    jmethodID addTag;
+} gAudioAttributesBuilderMethods;
+
+
+static jint nativeAudioAttributesFromJavaAudioAttributes(
+        JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *aa)
+{
+    if (env == nullptr) {
+        return AUDIO_JAVA_DEAD_OBJECT;
+    }
+    if (jAudioAttributes == nullptr) {
+        ALOGE("Invalid AudioAttributes java object");
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    const jstring jtags =
+            (jstring) env->GetObjectField(jAudioAttributes, gAudioAttributesFields.mFormattedTags);
+    if (jtags == nullptr) {
+        return AUDIO_JAVA_NO_INIT;
+    }
+    const char* tags = env->GetStringUTFChars(jtags, NULL);
+    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+    strncpy(aa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    env->ReleaseStringUTFChars(jtags, tags);
+
+    // Record ?
+    aa->source = (audio_source_t) env->GetIntField(jAudioAttributes,
+                                                    gAudioAttributesFields.mSource);
+    // Track ?
+    aa->usage = (audio_usage_t) env->GetIntField(jAudioAttributes, gAudioAttributesFields.mUsage);
+
+    aa->content_type =
+            (audio_content_type_t) env->GetIntField(jAudioAttributes,
+                                                    gAudioAttributesFields.mContentType);
+
+    aa->flags = (audio_flags_mask_t)env->GetIntField(jAudioAttributes,
+                                                      gAudioAttributesFields.mFlags);
+
+    ALOGV("AudioAttributes for usage=%d content=%d source=%d tags=%s flags=%08x tags=%s",
+          aa->usage, aa->content_type, aa->source, aa->tags, aa->flags, aa->tags);
+    return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+static jint nativeAudioAttributesToJavaAudioAttributes(
+        JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
+{
+    ScopedLocalRef<jobject> jAttributeBuilder(env, env->NewObject(gAudioAttributesBuilderClass,
+                                                                  gAudioAttributesBuilderCstor));
+    if (jAttributeBuilder.get() == nullptr) {
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setUsage,
+                          attributes.usage);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setInternalCapturePreset,
+                          attributes.source);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setContentType,
+                          attributes.content_type);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setFlags,
+                          attributes.flags);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.addTag,
+                          env->NewStringUTF(attributes.tags));
+
+    *jAudioAttributes = env->CallObjectMethod(jAttributeBuilder.get(),
+                                              gAudioAttributesBuilderMethods.build);
+    return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+// ----------------------------------------------------------------------------
+JNIAudioAttributeHelper::UniqueAaPtr JNIAudioAttributeHelper::makeUnique()
+{
+    audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t)))
+                audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER};
+    return UniqueAaPtr{aa, free};
+}
+
+jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes,
+                                             audio_attributes_t *paa)
+{
+    return nativeAudioAttributesFromJavaAudioAttributes(env, jAudioAttributes, paa);
+}
+
+jint JNIAudioAttributeHelper::nativeToJava(
+        JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
+{
+    return nativeAudioAttributesToJavaAudioAttributes(env, jAudioAttributes, attributes);
+}
+
+jint JNIAudioAttributeHelper::getJavaArray(
+        JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes)
+{
+    *jAudioAttributeArray = env->NewObjectArray(numAudioAttributes, gAudioAttributesClass, NULL);
+    return jAudioAttributeArray == NULL? (jint)AUDIO_JAVA_ERROR : (jint)AUDIO_JAVA_SUCCESS;
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    // n/a
+};
+
+int register_android_media_AudioAttributes(JNIEnv *env)
+{
+    jclass audioAttributesClass = FindClassOrDie(env, kClassPathName);
+    gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
+    gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
+    gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
+    gAudioAttributesFields.mContentType =
+            GetFieldIDOrDie(env, audioAttributesClass, "mContentType", "I");
+    gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
+    gAudioAttributesFields.mFormattedTags =
+            GetFieldIDOrDie(env, audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
+
+    jclass audioAttributesBuilderClass = FindClassOrDie(
+                env, "android/media/AudioAttributes$Builder");
+    gAudioAttributesBuilderClass = MakeGlobalRefOrDie(env, audioAttributesBuilderClass);
+    gAudioAttributesBuilderCstor = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "<init>", "()V");
+    gAudioAttributesBuilderMethods.build = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "build", "()Landroid/media/AudioAttributes;");
+    gAudioAttributesBuilderMethods.setUsage = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setUsage",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setInternalCapturePreset = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setInternalCapturePreset",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setContentType = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setContentType",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setFlags = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setFlags",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.addTag = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "addTag",
+                "(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder;");
+
+    env->DeleteLocalRef(audioAttributesClass);
+
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_media_AudioAttributes.h b/core/jni/android_media_AudioAttributes.h
new file mode 100644
index 0000000..c558352
--- /dev/null
+++ b/core/jni/android_media_AudioAttributes.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "jni.h"
+
+#include <memory.h>
+
+#include <system/audio.h>
+
+namespace android {
+
+class JNIAudioAttributeHelper
+{
+public:
+    using UniqueAaPtr = std::unique_ptr<audio_attributes_t, decltype(free)*>;
+
+    /**
+     * @brief makeUnique helper to prevent leak
+     * @return a unique ptr of 0-initialized native audio attributes structure
+     */
+    static UniqueAaPtr makeUnique();
+
+    /**
+     * @brief nativeFromJava Gets the underlying AudioAttributes from an AudioAttributes Java
+     * object.
+     * @param env
+     * @param jAudioAttributes JAVA AudioAttribute object
+     * @param paa native AudioAttribute pointer
+     * @return AUDIO_JAVA_SUCCESS on success, error code otherwise
+     */
+    static jint nativeFromJava(
+            JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *attributes);
+
+    /**
+     * @brief nativeToJava AudioAttributes Java object from a native AudioAttributes.
+     * @param env
+     * @param jAudioAttributes JAVA AudioAttribute object
+     * @param attributes native AudioAttribute
+     * @return AUDIO_JAVA_SUCCESS on success, error code otherwise
+     */
+    static jint nativeToJava(
+            JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes);
+
+    /**
+     * @brief getJavaArray: creates an array of JAVA AudioAttributes objects
+     * @param env
+     * @param jAudioAttributeArray
+     * @param numAudioAttributes
+     * @return Array of AudioAttributes objects
+     */
+    static jint getJavaArray(
+            JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes);
+};
+
+}; // namespace android
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 67c3064..02dffdc2 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -35,6 +35,7 @@
 #include "android_media_DeviceCallback.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_MicrophoneInfo.h"
+#include "android_media_AudioAttributes.h"
 
 // ----------------------------------------------------------------------------
 
@@ -42,7 +43,6 @@
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/AudioRecord";
-static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
 
 static jclass gArrayListClass;
 static struct {
@@ -56,12 +56,6 @@
     jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
     jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
 };
-struct audio_attributes_fields_t {
-    jfieldID  fieldRecSource;    // AudioAttributes.mSource
-    jfieldID  fieldFlags;        // AudioAttributes.mFlags
-    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
-};
-static audio_attributes_fields_t javaAudioAttrFields;
 static audio_record_fields_t     javaAudioRecordFields;
 static struct {
     jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
@@ -213,7 +207,6 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    audio_attributes_t *paa = NULL;
     sp<AudioRecord> lpRecorder = 0;
     audiorecord_callback_cookie *lpCallbackData = NULL;
 
@@ -275,15 +268,11 @@
         lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
 
         // read the AudioAttributes values
-        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        const jstring jtags =
-                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-        const char* tags = env->GetStringUTFChars(jtags, NULL);
-        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-        env->ReleaseStringUTFChars(jtags, tags);
-        paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
-        paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+        auto paa = JNIAudioAttributeHelper::makeUnique();
+        jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+        if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+            return jStatus;
+        }
         ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
 
         audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
@@ -311,7 +300,7 @@
             AudioRecord::TRANSFER_DEFAULT,
             flags,
             -1, -1,        // default uid, pid
-            paa);
+            paa.get());
 
         if (status != NO_ERROR) {
             ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
@@ -368,19 +357,10 @@
     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
 
-    if (paa != NULL) {
-        // audio attributes were copied in AudioRecord creation
-        free(paa);
-        paa = NULL;
-    }
-
     return (jint) AUDIO_JAVA_SUCCESS;
 
     // failure:
 native_init_failure:
-    if (paa != NULL) {
-        free(paa);
-    }
     env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
     env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
     delete lpCallbackData;
@@ -972,13 +952,6 @@
     javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
             audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
 
-    // Get the AudioAttributes class and fields
-    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
-    javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
-    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
-            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
-
     // Get the RecordTimestamp class and fields
     jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
     javaAudioTimestampFields.fieldFramePosition =
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 0d8ede7..34abcd8 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -36,6 +36,7 @@
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 #include "android_media_MicrophoneInfo.h"
+#include "android_media_AudioAttributes.h"
 
 // ----------------------------------------------------------------------------
 
@@ -153,15 +154,6 @@
     jfieldID    mRule;
 } gAudioMixMatchCriterionFields;
 
-static jclass gAudioAttributesClass;
-static struct {
-    jfieldID    mUsage;
-    jfieldID    mSource;
-    jfieldID    mContentType;
-    jfieldID    mFlags;
-    jfieldID    mFormattedTags;
-} gAudioAttributesFields;
-
 static const char* const kEventHandlerClassPathName =
         "android/media/AudioPortEventHandler";
 static struct {
@@ -705,27 +697,6 @@
     env->DeleteLocalRef(jValues);
 }
 
-static jint convertAudioAttributesToNative(JNIEnv *env,
-                                           audio_attributes_t *nAudioAttributes,
-                                           const jobject jAudioAttributes)
-{
-    nAudioAttributes->usage = (audio_usage_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mUsage);
-    nAudioAttributes->source = (audio_source_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mSource);
-    nAudioAttributes->content_type = (audio_content_type_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mContentType);
-    nAudioAttributes->flags = env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mFlags);
-    const jstring jtags = (jstring)env->GetObjectField(jAudioAttributes,
-            gAudioAttributesFields.mFormattedTags);
-    const char *tags = env->GetStringUTFChars(jtags, NULL);
-    strncpy(nAudioAttributes->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-    env->ReleaseStringUTFChars(jtags, tags);
-    return (jint)AUDIO_JAVA_SUCCESS;
-}
-
-
 static jint convertAudioPortConfigToNative(JNIEnv *env,
                                                struct audio_port_config *nAudioPortConfig,
                                                const jobject jAudioPortConfig,
@@ -1705,22 +1676,19 @@
     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
         return AUDIO_JAVA_BAD_VALUE;
     }
-    if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
-        return AUDIO_JAVA_BAD_VALUE;
-    }
     struct audio_port_config nAudioPortConfig = {};
     jint jStatus = convertAudioPortConfigToNativeWithDevicePort(env,
             &nAudioPortConfig, jAudioPortConfig, false);
     if (jStatus != AUDIO_JAVA_SUCCESS) {
         return jStatus;
     }
-    audio_attributes_t nAudioAttributes = {};
-    jStatus = convertAudioAttributesToNative(env, &nAudioAttributes, jAudioAttributes);
-    if (jStatus != AUDIO_JAVA_SUCCESS) {
+    auto paa = JNIAudioAttributeHelper::makeUnique();
+    jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
+    if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
         return jStatus;
     }
     audio_port_handle_t handle;
-    status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, &nAudioAttributes, &handle);
+    status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, paa.get(), &handle);
     ALOGV("AudioSystem::startAudioSource() returned %d handle %d", status, handle);
     return handle > 0 ? handle : nativeToJavaStatus(status);
 }
@@ -1833,12 +1801,16 @@
         case RULE_MATCH_ATTRIBUTE_USAGE:
         case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
             jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+
+            auto paa = JNIAudioAttributeHelper::makeUnique();
+            jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
+            if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+                return jStatus;
+            }
             if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
-                nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
-                        gAudioAttributesFields.mUsage);
+                nCriterion.mValue.mUsage = paa->usage;
             } else {
-                nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
-                        gAudioAttributesFields.mSource);
+                nCriterion.mValue.mSource = paa->source;
             }
             env->DeleteLocalRef(jAttributes);
             }
@@ -2395,17 +2367,6 @@
                                                        "I");
     gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
                                                        "I");
-
-    jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
-    gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
-    gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
-    gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
-    gAudioAttributesFields.mContentType = GetFieldIDOrDie(env,
-            audioAttributesClass, "mContentType", "I");
-    gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
-    gAudioAttributesFields.mFormattedTags = GetFieldIDOrDie(env,
-            audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
-
     // AudioTrackRoutingProxy methods
     gClsAudioTrackRoutingProxy =
             android::FindClassOrDie(env, "android/media/AudioTrackRoutingProxy");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a0d99ec..f9f28da 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -37,6 +37,7 @@
 #include "android_media_PlaybackParams.h"
 #include "android_media_DeviceCallback.h"
 #include "android_media_VolumeShaper.h"
+#include "android_media_AudioAttributes.h"
 
 #include <cinttypes>
 
@@ -48,7 +49,6 @@
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/AudioTrack";
-static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
 
 struct audio_track_fields_t {
     // these fields provide access from C++ to the...
@@ -57,14 +57,7 @@
     jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
     jfieldID  fieldStreamType; // ... mStreamType field in the AudioTrack Java object
 };
-struct audio_attributes_fields_t {
-    jfieldID  fieldUsage;        // AudioAttributes.mUsage
-    jfieldID  fieldContentType;  // AudioAttributes.mContentType
-    jfieldID  fieldFlags;        // AudioAttributes.mFlags
-    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
-};
 static audio_track_fields_t      javaAudioTrackFields;
-static audio_attributes_fields_t javaAudioAttrFields;
 static PlaybackParams::fields_t gPlaybackParamsFields;
 static VolumeShaperHelper::fields_t gVolumeShaperFields;
 
@@ -249,8 +242,6 @@
 
     AudioTrackJniStorage* lpJniStorage = NULL;
 
-    audio_attributes_t *paa = NULL;
-
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
         ALOGE("Can't find %s when setting up callback.", kClassPathName);
@@ -304,18 +295,11 @@
         lpTrack = new AudioTrack();
 
         // read the AudioAttributes values
-        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        const jstring jtags =
-                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-        const char* tags = env->GetStringUTFChars(jtags, NULL);
-        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-        env->ReleaseStringUTFChars(jtags, tags);
-        paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
-        paa->content_type =
-                (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
-        paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
-
+        auto paa = JNIAudioAttributeHelper::makeUnique();
+        jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+        if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+            return jStatus;
+        }
         ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
                 paa->usage, paa->content_type, paa->flags, paa->tags);
 
@@ -357,7 +341,7 @@
                     offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
                     offload ? &offloadInfo : NULL,
                     -1, -1,                       // default uid, pid values
-                    paa);
+                    paa.get());
 
             break;
 
@@ -384,7 +368,7 @@
                     AudioTrack::TRANSFER_SHARED,
                     NULL,                         // default offloadInfo
                     -1, -1,                       // default uid, pid values
-                    paa);
+                    paa.get());
             break;
 
         default:
@@ -452,20 +436,11 @@
     // since we had audio attributes, the stream type was derived from them during the
     // creation of the native AudioTrack: push the same value to the Java object
     env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
-    if (paa != NULL) {
-        // audio attributes were copied in AudioTrack creation
-        free(paa);
-        paa = NULL;
-    }
-
 
     return (jint) AUDIO_JAVA_SUCCESS;
 
     // failures:
 native_init_failure:
-    if (paa != NULL) {
-        free(paa);
-    }
     if (nSession != NULL) {
         env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     }
@@ -1470,17 +1445,6 @@
 
     env->DeleteLocalRef(audioTrackClass);
 
-    // Get the AudioAttributes class and fields
-    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
-    javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
-    javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
-            audioAttrClass, "mContentType", "I");
-    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
-            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
-
-    env->DeleteLocalRef(audioAttrClass);
-
     // initialize PlaybackParams field info
     gPlaybackParamsFields.init(env);
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b8139a7..f9407f4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -131,6 +131,7 @@
     switch(f) {
         case PublicFormat::JPEG:
         case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH_JPEG:
             return HAL_PIXEL_FORMAT_BLOB;
         case PublicFormat::DEPTH16:
             return HAL_PIXEL_FORMAT_Y16;
@@ -161,6 +162,8 @@
         case PublicFormat::NV21:
         case PublicFormat::YV12:
             return HAL_DATASPACE_V0_JFIF;
+        case PublicFormat::DEPTH_JPEG:
+            return static_cast<android_dataspace> (HAL_DATASPACE_DYNAMIC_DEPTH);
         default:
             // Most formats map to UNKNOWN
             return HAL_DATASPACE_UNKNOWN;
@@ -223,8 +226,12 @@
                 case HAL_DATASPACE_V0_JFIF:
                     return PublicFormat::JPEG;
                 default:
-                    // Assume otherwise-marked blobs are also JPEG
-                    return PublicFormat::JPEG;
+                    if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
+                        return PublicFormat::DEPTH_JPEG;
+                    } else {
+                        // Assume otherwise-marked blobs are also JPEG
+                        return PublicFormat::JPEG;
+                    }
             }
             break;
         case HAL_PIXEL_FORMAT_BGRA_8888:
diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp
index 50b2288..76b0fc1 100644
--- a/core/jni/com_android_internal_os_AtomicDirectory.cpp
+++ b/core/jni/com_android_internal_os_AtomicDirectory.cpp
@@ -29,7 +29,7 @@
         return -1;
     }
     int fd;
-    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY))) == -1) {
+    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC))) == -1) {
         ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno));
         return -1;
     }
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 36487b3..984e942 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -57,7 +57,8 @@
     YV12              = 0x32315659,
     Y8                = 0x20203859, // @hide
     Y16               = 0x20363159, // @hide
-    DEPTH16           = 0x44363159
+    DEPTH16           = 0x44363159,
+    DEPTH_JPEG        = 0x69656963,
 };
 
 /* Gets the underlying ANativeWindow for a Surface. */
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
index 80cc2d4..3b891d6 100644
--- a/core/proto/Android.bp
+++ b/core/proto/Android.bp
@@ -21,7 +21,10 @@
         type: "lite",
     },
     srcs: [
+        "android/bluetooth/a2dp/enums.proto",
         "android/bluetooth/enums.proto",
         "android/bluetooth/hci/enums.proto",
+        "android/bluetooth/hfp/enums.proto",
+        "android/bluetooth/smp/enums.proto",
     ],
 }
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index bba8328..f702b3e 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -18,6 +18,9 @@
 
 package android.app.job;
 
+// This file is for JobScheduler enums inside the app directory. If you're
+// adding enums for system-server-side code, use the file in
+// frameworks/base/core/proto/android/server/job.
 option java_outer_classname = "JobProtoEnums";
 option java_multiple_files = true;
 
diff --git a/core/proto/android/bluetooth/a2dp/enums.proto b/core/proto/android/bluetooth/a2dp/enums.proto
new file mode 100644
index 0000000..5a025bd
--- /dev/null
+++ b/core/proto/android/bluetooth/a2dp/enums.proto
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.a2dp;
+
+option java_outer_classname = "BluetoothA2dpProtoEnums";
+option java_multiple_files = true;
+
+// A2dp playback state enum, defined from:
+// frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java
+enum PlaybackStateEnum {
+    PLAYBACK_STATE_UNKNOWN = 0;
+    PLAYBACK_STATE_PLAYING = 10;
+    PLAYBACK_STATE_NOT_PLAYING = 11;
+}
+
+enum AudioCodingModeEnum {
+    AUDIO_CODING_MODE_UNKNOWN = 0;
+    AUDIO_CODING_MODE_HARDWARE = 1;
+    AUDIO_CODING_MODE_SOFTWARE = 2;
+}
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 76c240e..a88a06c 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -56,3 +56,57 @@
     LINK_TYPE_ACL = 0x01;
     LINK_TYPE_ESCO = 0x02;
 }
+
+enum DeviceInfoSrcEnum {
+    DEVICE_INFO_SRC_UNKNOWN = 0;
+    // Within Android Bluetooth stack
+    DEVICE_INFO_INTERNAL = 1;
+    // Outside Android Bluetooth stack
+    DEVICE_INFO_EXTERNAL = 2;
+}
+
+enum DeviceTypeEnum {
+    DEVICE_TYPE_UNKNOWN = 0;
+    DEVICE_TYPE_CLASSIC = 1;
+    DEVICE_TYPE_LE = 2;
+    DEVICE_TYPE_DUAL = 3;
+}
+
+// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+enum TransportTypeEnum {
+    TRANSPORT_TYPE_AUTO = 0;
+    TRANSPORT_TYPE_BREDR = 1;
+    TRANSPORT_TYPE_LE = 2;
+}
+
+// Bond state enum
+// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+enum BondStateEnum {
+    BOND_STATE_UNKNOWN = 0;
+    BOND_STATE_NONE = 10;
+    BOND_STATE_BONDING = 11;
+    BOND_STATE_BONDED = 12;
+}
+
+// Sub states within the bonding general state
+enum BondSubStateEnum {
+    BOND_SUB_STATE_UNKNOWN = 0;
+    BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED = 1;
+    BOND_SUB_STATE_LOCAL_PIN_REQUESTED = 2;
+    BOND_SUB_STATE_LOCAL_PIN_REPLIED = 3;
+    BOND_SUB_STATE_LOCAL_SSP_REQUESTED = 4;
+    BOND_SUB_STATE_LOCAL_SSP_REPLIED = 5;
+}
+
+enum UnbondReasonEnum {
+    UNBOND_REASON_UNKNOWN = 0;
+    UNBOND_REASON_AUTH_FAILED = 1;
+    UNBOND_REASON_AUTH_REJECTED = 2;
+    UNBOND_REASON_AUTH_CANCELED = 3;
+    UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
+    UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
+    UNBOND_REASON_AUTH_TIMEOUT = 6;
+    UNBOND_REASON_REPEATED_ATTEMPTS = 7;
+    UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
+    UNBOND_REASON_REMOVED = 9;
+}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
index e1d96bb..ef894e5 100644
--- a/core/proto/android/bluetooth/hci/enums.proto
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -351,7 +351,7 @@
     EVT_COMMAND_COMPLETE = 0x0E;
     EVT_COMMAND_STATUS = 0x0F;
     EVT_HARDWARE_ERROR = 0x10;
-    EVT_FLUSH_OCCURED = 0x11;
+    EVT_FLUSH_OCCURRED = 0x11;
     EVT_ROLE_CHANGE = 0x12;
     EVT_NUM_COMPL_DATA_PKTS = 0x13;
     EVT_MODE_CHANGE = 0x14;
@@ -517,3 +517,43 @@
     STATUS_CLB_DATA_TOO_BIG = 0x43;
     STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
 }
+
+enum BqrIdEnum {
+    BQR_ID_UNKNOWN = 0x00;
+    BQR_ID_MONITOR_MODE = 0x01;
+    BQR_ID_APPROACH_LSTO = 0x02;
+    BQR_ID_A2DP_AUDIO_CHOPPY = 0x03;
+    BQR_ID_SCO_VOICE_CHOPPY = 0x04;
+}
+
+enum BqrPacketTypeEnum {
+    BQR_PACKET_TYPE_UNKNOWN = 0x00;
+    BQR_PACKET_TYPE_ID = 0x01;
+    BQR_PACKET_TYPE_NULL = 0x02;
+    BQR_PACKET_TYPE_POLL = 0x03;
+    BQR_PACKET_TYPE_FHS = 0x04;
+    BQR_PACKET_TYPE_HV1 = 0x05;
+    BQR_PACKET_TYPE_HV2 = 0x06;
+    BQR_PACKET_TYPE_HV3 = 0x07;
+    BQR_PACKET_TYPE_DV = 0x08;
+    BQR_PACKET_TYPE_EV3 = 0x09;
+    BQR_PACKET_TYPE_EV4 = 0x0A;
+    BQR_PACKET_TYPE_EV5 = 0x0B;
+    BQR_PACKET_TYPE_2EV3 = 0x0C;
+    BQR_PACKET_TYPE_2EV5 = 0x0D;
+    BQR_PACKET_TYPE_3EV3 = 0x0E;
+    BQR_PACKET_TYPE_3EV5 = 0x0F;
+    BQR_PACKET_TYPE_DM1 = 0x10;
+    BQR_PACKET_TYPE_DH1 = 0x11;
+    BQR_PACKET_TYPE_DM3 = 0x12;
+    BQR_PACKET_TYPE_DH3 = 0x13;
+    BQR_PACKET_TYPE_DM5 = 0x14;
+    BQR_PACKET_TYPE_DH5 = 0x15;
+    BQR_PACKET_TYPE_AUX1 = 0x16;
+    BQR_PACKET_TYPE_2DH1 = 0x17;
+    BQR_PACKET_TYPE_2DH3 = 0x18;
+    BQR_PACKET_TYPE_2DH5 = 0x19;
+    BQR_PACKET_TYPE_3DH1 = 0x1A;
+    BQR_PACKET_TYPE_3DH3 = 0x1B;
+    BQR_PACKET_TYPE_3DH5 = 0x1C;
+}
diff --git a/core/proto/android/bluetooth/smp/enums.proto b/core/proto/android/bluetooth/smp/enums.proto
new file mode 100644
index 0000000..c6747b7
--- /dev/null
+++ b/core/proto/android/bluetooth/smp/enums.proto
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.smp;
+
+option java_outer_classname = "BluetoothSmpProtoEnums";
+option java_multiple_files = true;
+
+// SMP Pairing command codes
+enum CommandEnum {
+    CMD_UNKNOWN = 0x00;
+    CMD_PAIRING_REQUEST = 0x01;
+    CMD_PAIRING_RESPONSE = 0x02;
+    CMD_PAIRING_CONFIRM = 0x03;
+    CMD_PAIRING_RANDOM = 0x04;
+    CMD_PAIRING_FAILED = 0x05;
+    CMD_ENCRYPTION_INFON = 0x06;
+    CMD_MASTER_IDENTIFICATION = 0x07;
+    CMD_IDENTITY_INFO = 0x08;
+    CMD_IDENTITY_ADDR_INFO = 0x09;
+    CMD_SIGNING_INFO = 0x0A;
+    CMD_SECURITY_REQUEST = 0x0B;
+    CMD_PAIRING_PUBLIC_KEY = 0x0C;
+    CMD_PAIRING_DHKEY_CHECK = 0x0D;
+    CMD_PAIRING_KEYPRESS_INFO = 0x0E;
+}
+
+enum PairingFailReasonEnum {
+    PAIRING_FAIL_REASON_RESERVED = 0x00;
+    PAIRING_FAIL_REASON_PASSKEY_ENTRY = 0x01;
+    PAIRING_FAIL_REASON_OOB = 0x02;
+    PAIRING_FAIL_REASON_AUTH_REQ = 0x03;
+    PAIRING_FAIL_REASON_CONFIRM_VALUE = 0x04;
+    PAIRING_FAIL_REASON_PAIR_NOT_SUPPORT = 0x05;
+    PAIRING_FAIL_REASON_ENC_KEY_SIZE = 0x06;
+    PAIRING_FAIL_REASON_INVALID_CMD = 0x07;
+    PAIRING_FAIL_REASON_UNSPECIFIED = 0x08;
+    PAIRING_FAIL_REASON_REPEATED_ATTEMPTS = 0x09;
+    PAIRING_FAIL_REASON_INVALID_PARAMETERS = 0x0A;
+    PAIRING_FAIL_REASON_DHKEY_CHK = 0x0B;
+    PAIRING_FAIL_REASON_NUMERIC_COMPARISON = 0x0C;
+    PAIRING_FAIL_REASON_CLASSIC_PAIRING_IN_PROGR = 0x0D;
+    PAIRING_FAIL_REASON_XTRANS_DERIVE_NOT_ALLOW = 0x0E;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/job/enums.proto b/core/proto/android/server/job/enums.proto
new file mode 100644
index 0000000..50fc031
--- /dev/null
+++ b/core/proto/android/server/job/enums.proto
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+
+package com.android.server.job;
+
+// This file is for JobScheduler enums inside the server directory. If you're
+// adding enums for app-side code, use the file in
+// frameworks/base/core/proto/android/app/job.
+option java_outer_classname = "JobServerProtoEnums";
+option java_multiple_files = true;
+
+// Set of constraints that a job potentially needs satisfied before it can run.
+// Defined in
+// frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
+enum ConstraintEnum {
+    CONSTRAINT_UNKNOWN = 0;
+    CONSTRAINT_CHARGING = 1;
+    CONSTRAINT_BATTERY_NOT_LOW = 2;
+    CONSTRAINT_STORAGE_NOT_LOW = 3;
+    CONSTRAINT_TIMING_DELAY = 4;
+    CONSTRAINT_DEADLINE = 5;
+    CONSTRAINT_IDLE = 6;
+    CONSTRAINT_CONNECTIVITY = 7;
+    CONSTRAINT_CONTENT_TRIGGER = 8;
+    CONSTRAINT_DEVICE_NOT_DOZING = 9;
+    CONSTRAINT_WITHIN_QUOTA = 10;
+    CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 11;
+}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 188769d..6c9d13a 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -29,6 +29,7 @@
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
 import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 // Next tag: 21
@@ -757,21 +758,9 @@
     }
     optional JobInfo job_info = 6;
 
-    enum Constraint {
-        CONSTRAINT_CHARGING = 1;
-        CONSTRAINT_BATTERY_NOT_LOW = 2;
-        CONSTRAINT_STORAGE_NOT_LOW = 3;
-        CONSTRAINT_TIMING_DELAY = 4;
-        CONSTRAINT_DEADLINE = 5;
-        CONSTRAINT_IDLE = 6;
-        CONSTRAINT_CONNECTIVITY = 7;
-        CONSTRAINT_CONTENT_TRIGGER = 8;
-        CONSTRAINT_DEVICE_NOT_DOZING = 9;
-        CONSTRAINT_WITHIN_QUOTA = 10;
-    }
-    repeated Constraint required_constraints = 7;
-    repeated Constraint satisfied_constraints = 8;
-    repeated Constraint unsatisfied_constraints = 9;
+    repeated ConstraintEnum required_constraints = 7;
+    repeated ConstraintEnum satisfied_constraints = 8;
+    repeated ConstraintEnum unsatisfied_constraints = 9;
     optional bool is_doze_whitelisted = 10;
     optional bool is_uid_active = 26;
 
diff --git a/packages/SettingsLib/res/drawable/btn_borderless_rect.xml b/core/res/res/drawable/btn_borderless_rect.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/btn_borderless_rect.xml
rename to core/res/res/drawable/btn_borderless_rect.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_cellphone.xml b/core/res/res/drawable/ic_bt_cellphone.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_cellphone.xml
rename to core/res/res/drawable/ic_bt_cellphone.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml b/core/res/res/drawable/ic_bt_headphones_a2dp.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml
rename to core/res/res/drawable/ic_bt_headphones_a2dp.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml b/core/res/res/drawable/ic_bt_headset_hfp.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml
rename to core/res/res/drawable/ic_bt_headset_hfp.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/core/res/res/drawable/ic_bt_hearing_aid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
rename to core/res/res/drawable/ic_bt_hearing_aid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_laptop.xml b/core/res/res/drawable/ic_bt_laptop.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_laptop.xml
rename to core/res/res/drawable/ic_bt_laptop.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml b/core/res/res/drawable/ic_bt_misc_hid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml
rename to core/res/res/drawable/ic_bt_misc_hid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_network_pan.xml b/core/res/res/drawable/ic_bt_network_pan.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_network_pan.xml
rename to core/res/res/drawable/ic_bt_network_pan.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml b/core/res/res/drawable/ic_bt_pointing_hid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml
rename to core/res/res/drawable/ic_bt_pointing_hid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_expand_more.xml b/core/res/res/drawable/ic_expand_more.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_expand_more.xml
rename to core/res/res/drawable/ic_expand_more.xml
diff --git a/packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml b/core/res/res/drawable/ic_lockscreen_ime.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml
rename to core/res/res/drawable/ic_lockscreen_ime.xml
diff --git a/packages/SettingsLib/res/drawable/ic_menu.xml b/core/res/res/drawable/ic_menu.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_menu.xml
rename to core/res/res/drawable/ic_menu.xml
diff --git a/packages/SettingsLib/res/drawable/ic_minus.xml b/core/res/res/drawable/ic_minus.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_minus.xml
rename to core/res/res/drawable/ic_minus.xml
diff --git a/packages/SettingsLib/res/drawable/ic_mode_edit.xml b/core/res/res/drawable/ic_mode_edit.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_mode_edit.xml
rename to core/res/res/drawable/ic_mode_edit.xml
diff --git a/packages/SettingsLib/res/drawable/ic_plus.xml b/core/res/res/drawable/ic_plus.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_plus.xml
rename to core/res/res/drawable/ic_plus.xml
diff --git a/packages/SettingsLib/res/drawable/ic_qs_night_display_on.xml b/core/res/res/drawable/ic_qs_night_display_on.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_qs_night_display_on.xml
rename to core/res/res/drawable/ic_qs_night_display_on.xml
diff --git a/packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml b/core/res/res/drawable/ic_settings_bluetooth.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml
rename to core/res/res/drawable/ic_settings_bluetooth.xml
diff --git a/packages/SettingsLib/res/drawable/ic_settings_print.xml b/core/res/res/drawable/ic_settings_print.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_settings_print.xml
rename to core/res/res/drawable/ic_settings_print.xml
diff --git a/packages/SettingsLib/res/drawable/ic_signal_location.xml b/core/res/res/drawable/ic_signal_location.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_signal_location.xml
rename to core/res/res/drawable/ic_signal_location.xml
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 43b3552..949c12e 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -51,6 +51,10 @@
           -->
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
     <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault">
+        <item name="windowLightStatusBar">false</item>
+        <item name="navigationBarColor">@android:color/black</item>
+        <item name="windowLightNavigationBar">false</item>
+
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorBackground">@color/primary_dark_device_default_settings</item>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f79e22d..47bd9da 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1423,6 +1423,27 @@
   <java-symbol type="drawable" name="ic_sim_card_multi_48px_clr" />
   <java-symbol type="drawable" name="ic_signal_cellular_alt_24px" />
 
+  <java-symbol type="drawable" name="btn_borderless_rect" />
+  <java-symbol type="drawable" name="ic_bt_cellphone" />
+  <java-symbol type="drawable" name="ic_bt_headphones_a2dp" />
+  <java-symbol type="drawable" name="ic_bt_headset_hfp" />
+  <java-symbol type="drawable" name="ic_bt_hearing_aid" />
+  <java-symbol type="drawable" name="ic_bt_laptop" />
+  <java-symbol type="drawable" name="ic_bt_misc_hid" />
+  <java-symbol type="drawable" name="ic_bt_network_pan" />
+  <java-symbol type="drawable" name="ic_bt_pointing_hid" />
+  <java-symbol type="drawable" name="ic_expand_more" />
+  <java-symbol type="drawable" name="ic_lockscreen_ime" />
+  <java-symbol type="drawable" name="ic_menu" />
+  <java-symbol type="drawable" name="ic_minus" />
+  <java-symbol type="drawable" name="ic_mode_edit" />
+  <java-symbol type="drawable" name="ic_plus" />
+  <java-symbol type="drawable" name="ic_qs_night_display_on" />
+  <java-symbol type="drawable" name="ic_settings_bluetooth" />
+  <java-symbol type="drawable" name="ic_settings_print" />
+  <java-symbol type="drawable" name="ic_signal_location" />
+  <java-symbol type="drawable" name="ic_info_outline_24" />
+
   <java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
   <java-symbol type="drawable" name="autofilled_highlight"/>
   <java-symbol type="drawable" name="ic_camera" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index bd7f852..2a29f83 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -132,6 +132,9 @@
                     Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
+                    Settings.Global.BROADCAST_BG_CONSTANTS,
+                    Settings.Global.BROADCAST_FG_CONSTANTS,
+                    Settings.Global.BROADCAST_OFFLOAD_CONSTANTS,
                     Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
                     Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
                     Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 904c3fb..1684138 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -87,6 +87,7 @@
         <permission name="android.permission.MASTER_CLEAR"/>
         <permission name="android.permission.NETWORK_MANAGED_PROVISIONING"/>
         <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.SET_TIME"/>
         <permission name="android.permission.SET_TIME_ZONE"/>
         <permission name="android.permission.SHUTDOWN"/>
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index c580c46..0787d85 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -183,6 +183,14 @@
     public static final int JPEG = 0x100;
 
     /**
+     * Depth augmented compressed JPEG format.
+     *
+     * <p>JPEG compressed main image along with XMP embedded depth metadata
+     * following ISO 16684-1:2011(E).</p>
+     */
+    public static final int DEPTH_JPEG = 0x69656963;
+
+    /**
      * <p>Multi-plane Android YUV 420 format</p>
      *
      * <p>This format is a generic YCbCr format, capable of describing any 4:2:0
@@ -787,6 +795,7 @@
             case PRIVATE:
             case RAW_DEPTH:
             case Y8:
+            case DEPTH_JPEG:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 25f6775..cb1f69c 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -33,6 +33,7 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -46,6 +47,7 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
+import dalvik.system.VMRuntime;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -243,7 +245,16 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(fontBuilder.build());
                 } else {
-                    familyBuilder.addFont(fontBuilder.build());
+                    try {
+                        familyBuilder.addFont(fontBuilder.build());
+                    } catch (IllegalArgumentException e) {
+                        if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) {
+                            // Surpress the IllegalArgumentException for keeping the backward
+                            // compatibility.
+                            continue;
+                        }
+                        throw e;
+                    }
                 }
             }
             if (familyBuilder == null) {
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index a2feec2..6a90c17 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -4482,6 +4482,7 @@
     };
 
     // Modular DRM
+    private final Map<UUID, MediaDrm> mDrmObjs = new HashMap<>();
     private class DrmHandle {
 
         static final int PROVISION_TIMEOUT_MS = 60000;
@@ -4594,7 +4595,13 @@
             Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
 
             try {
-                mDrmObj = new MediaDrm(uuid);
+                mDrmObj = mDrmObjs.computeIfAbsent(uuid, scheme -> {
+                    try {
+                        return new MediaDrm(scheme);
+                    } catch (UnsupportedSchemeException e) {
+                        throw new IllegalArgumentException(e);
+                    }
+                });
                 Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
             } catch (Exception e) { // UnsupportedSchemeException
                 Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 9ac147b..60ef1d9 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -17,12 +17,10 @@
 package android.media;
 
 import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
 import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
 import android.view.Surface;
 
 import dalvik.system.VMRuntime;
@@ -74,12 +72,6 @@
     private static final int ACQUIRE_MAX_IMAGES = 2;
 
     /**
-     * Invalid consumer buffer usage flag. This usage flag will be ignored
-     * by the {@code ImageReader} instance is constructed with this value.
-     */
-    private static final long BUFFER_USAGE_UNKNOWN = 0;
-
-    /**
      * <p>
      * Create a new reader for images of the desired size and format.
      * </p>
@@ -129,7 +121,10 @@
      * @see Image
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages) {
-        return new ImageReader(width, height, format, maxImages, BUFFER_USAGE_UNKNOWN);
+        // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
+        // work, and is inscrutable anyway
+        return new ImageReader(width, height, format, maxImages,
+                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN);
     }
 
     /**
@@ -207,18 +202,23 @@
      *            obtained by the user, one of them has to be released before a new Image will
      *            become available for access through {@link #acquireLatestImage()} or
      *            {@link #acquireNextImage()}. Must be greater than 0.
-     * @param usage The intended usage of the images produced by this ImageReader. It needs
-     *            to be one of the Usage defined by {@link HardwareBuffer}, or an
-     *            {@link IllegalArgumentException} will be thrown.
+     * @param usage The intended usage of the images produced by this ImageReader. See the usages
+     *              on {@link HardwareBuffer} for a list of valid usage bits. See also
+     *              {@link HardwareBuffer#isSupported(int, int, int, int, long)} for checking
+     *              if a combination is supported. If it's not supported this will throw
+     *              an {@link IllegalArgumentException}.
      * @see Image
      * @see HardwareBuffer
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages,
             long usage) {
-        if (!isFormatUsageCombinationAllowed(format, usage)) {
-            throw new IllegalArgumentException("Format usage combination is not supported:"
-                    + " format = " + format + ", usage = " + usage);
-        }
+        // TODO: Check this - can't do it just yet because format support is different
+        // Unify formats! The only reliable way to validate usage is to just try it and see.
+
+//        if (!HardwareBuffer.isSupported(width, height, format, 1, usage)) {
+//            throw new IllegalArgumentException("The given format=" + Integer.toHexString(format)
+//                + " & usage=" + Long.toHexString(usage) + " is not supported");
+//        }
         return new ImageReader(width, height, format, maxImages, usage);
     }
 
@@ -716,19 +716,6 @@
         return si.getReader() == this;
     }
 
-    private static boolean isFormatUsageCombinationAllowed(int format, long usage) {
-        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
-            return false;
-        }
-
-        // Valid usage needs to be provided.
-        if (usage == BUFFER_USAGE_UNKNOWN) {
-            return false;
-        }
-
-        return true;
-    }
-
     /**
      * Called from Native code when an Event happens.
      *
@@ -833,6 +820,7 @@
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
+                case ImageFormat.DEPTH_JPEG:
                     width = ImageReader.this.getWidth();
                     break;
                 default:
@@ -849,6 +837,7 @@
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
+                case ImageFormat.DEPTH_JPEG:
                     height = ImageReader.this.getHeight();
                     break;
                 default:
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index 2a0e04e..b77a884 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -63,6 +63,7 @@
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.RAW_DEPTH:
+            case ImageFormat.DEPTH_JPEG:
                 return 1;
             case ImageFormat.PRIVATE:
                 return 0;
@@ -192,6 +193,7 @@
             // 10x compression from RGB_888
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 estimatedBytePerPixel = 0.3;
                 break;
             case ImageFormat.Y8:
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 417a427..7168b2d 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -379,24 +379,9 @@
     String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
             width, height, format, maxImages, getpid(),
             createProcessUniqueId());
-    uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
-    bool needUsageOverride = ndkUsage != CONSUMER_BUFFER_USAGE_UNKNOWN;
-    uint64_t outProducerUsage = 0;
-    uint64_t outConsumerUsage = 0;
-    android_hardware_HardwareBuffer_convertToGrallocUsageBits(&outProducerUsage, &outConsumerUsage,
-            ndkUsage, 0);
+    uint64_t consumerUsage =
+            android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage);
 
-    if (isFormatOpaque(nativeFormat)) {
-        // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
-        // encoding. The only possibility will be ZSL output.
-        consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
-        if (needUsageOverride) {
-            consumerUsage = android_convertGralloc1To0Usage(0, outConsumerUsage);
-        }
-    } else if (needUsageOverride) {
-        ALOGW("Consumer usage override for non-opaque format is not implemented yet, "
-                "ignore the provided usage from the application");
-    }
     bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
             /*controlledByApp*/true);
     if (bufferConsumer == nullptr) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 5ab5092..0340cec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -857,7 +857,7 @@
         // JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
         // Same goes for DEPTH_POINT_CLOUD
         if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
-                format == ImageFormat.RAW_PRIVATE) {
+                format == ImageFormat.DEPTH_JPEG || format == ImageFormat.RAW_PRIVATE) {
             buffer = planes[0].getBuffer();
             assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
             data = new byte[buffer.remaining()];
@@ -940,6 +940,7 @@
             case ImageFormat.RAW_PRIVATE:
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 assertEquals("JPEG/RAW/depth Images should have one plane", 1, planes.length);
                 break;
             default:
@@ -1363,6 +1364,9 @@
             case ImageFormat.RAW_PRIVATE:
                 validateRawPrivateData(data, width, height, image.getTimestamp(), filePath);
                 break;
+            case ImageFormat.DEPTH_JPEG:
+                validateDepthJpegData(data, width, height, format, image.getTimestamp(), filePath);
+                break;
             default:
                 throw new UnsupportedOperationException("Unsupported format for validation: "
                         + format);
@@ -1528,6 +1532,23 @@
 
     }
 
+    private static void validateDepthJpegData(byte[] depthData, int width, int height, int format,
+            long ts, String filePath) {
+
+        if (VERBOSE) Log.v(TAG, "Validating depth jpeg data");
+
+        // Can't validate size since it is variable
+
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".jpg";
+            dumpFile(fileName, depthData);
+        }
+
+        return;
+
+    }
+
     public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         if (result == null) {
             throw new IllegalArgumentException("Result must not be null");
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index 8b00ed0..00b3736 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
+
 import com.android.printspooler.R;
 
 /**
@@ -366,7 +367,8 @@
             // and is janky. Now it is there but transparent, doing nothing.
             mEmbeddedContentScrim.setOnClickListener(null);
             mEmbeddedContentScrim.setClickable(false);
-            mExpandCollapseIcon.setBackgroundResource(R.drawable.ic_expand_more);
+            mExpandCollapseIcon.setBackgroundResource(
+                    com.android.internal.R.drawable.ic_expand_more);
         } else {
             if (mMoreOptionsButton.getVisibility() != View.GONE) {
                 mMoreOptionsButton.setVisibility(View.VISIBLE);
diff --git a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml b/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
deleted file mode 100644
index 46b8309..0000000
--- a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorSecondary">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,7h2v2h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,11h2v6h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8s8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
deleted file mode 100644
index 44b1866..0000000
--- a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 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.
--->
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_rotate_to_landscape"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:tint="?android:attr/colorControlNormal" >
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
-</vector>
diff --git a/packages/SettingsLib/res/drawable/notification_auto_importance.xml b/packages/SettingsLib/res/drawable/notification_auto_importance.xml
deleted file mode 100644
index c946153..0000000
--- a/packages/SettingsLib/res/drawable/notification_auto_importance.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-    Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M10.8,12.7l2.4,0l-1.2,-3.7z"/>
-    <path
-            android:fillColor="#FF000000"
-            android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM14.3,16l-0.7,-2h-3.2l-0.7,2H7.8L11,7h2l3.2,9H14.3z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/zen_mode_condition.xml b/packages/SettingsLib/res/layout/zen_mode_condition.xml
index c85a892..3222174 100644
--- a/packages/SettingsLib/res/layout/zen_mode_condition.xml
+++ b/packages/SettingsLib/res/layout/zen_mode_condition.xml
@@ -67,7 +67,7 @@
         android:layout_toStartOf="@android:id/button2"
         android:contentDescription="@string/accessibility_manual_zen_less_time"
         android:tint="?android:attr/colorAccent"
-        android:src="@drawable/ic_minus" />
+        android:src="@*android:drawable/ic_minus" />
 
     <ImageView
         android:id="@android:id/button2"
@@ -79,6 +79,6 @@
         android:layout_centerVertical="true"
         android:contentDescription="@string/accessibility_manual_zen_more_time"
         android:tint="?android:attr/colorAccent"
-        android:src="@drawable/ic_plus" />
+        android:src="@*android:drawable/ic_plus" />
 
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index bae8387..015f52c 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -24,7 +24,7 @@
 
     <style name="BorderlessButton">
         <item name="android:padding">12dp</item>
-        <item name="android:background">@drawable/btn_borderless_rect</item>
+        <item name="android:background">@*android:drawable/btn_borderless_rect</item>
         <item name="android:gravity">center</item>
     </style>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index c059156..bed3030 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -296,7 +296,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 873dd1a..4ce9d3e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -205,7 +205,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index ee80aa1..a8a0b6d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -61,13 +61,14 @@
         if (btClass != null) {
             switch (btClass.getMajorDeviceClass()) {
                 case BluetoothClass.Device.Major.COMPUTER:
-                    return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_bt_laptop, level,
-                            iconScale),
+                    return new Pair<>(getBluetoothDrawable(context,
+                            com.android.internal.R.drawable.ic_bt_laptop, level, iconScale),
                             context.getString(R.string.bluetooth_talkback_computer));
 
                 case BluetoothClass.Device.Major.PHONE:
                     return new Pair<>(
-                            getBluetoothDrawable(context, R.drawable.ic_bt_cellphone, level,
+                            getBluetoothDrawable(context,
+                                    com.android.internal.R.drawable.ic_bt_cellphone, level,
                                     iconScale),
                             context.getString(R.string.bluetooth_talkback_phone));
 
@@ -79,7 +80,8 @@
 
                 case BluetoothClass.Device.Major.IMAGING:
                     return new Pair<>(
-                            getBluetoothDrawable(context, R.drawable.ic_settings_print, level,
+                            getBluetoothDrawable(context,
+                                    com.android.internal.R.drawable.ic_settings_print, level,
                                     iconScale),
                             context.getString(R.string.bluetooth_talkback_imaging));
 
@@ -98,19 +100,22 @@
         if (btClass != null) {
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
                 return new Pair<>(
-                        getBluetoothDrawable(context, R.drawable.ic_bt_headset_hfp, level,
+                        getBluetoothDrawable(context,
+                                com.android.internal.R.drawable.ic_bt_headset_hfp, level,
                                 iconScale),
                         context.getString(R.string.bluetooth_talkback_headset));
             }
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
                 return new Pair<>(
-                        getBluetoothDrawable(context, R.drawable.ic_bt_headphones_a2dp, level,
+                        getBluetoothDrawable(context,
+                                com.android.internal.R.drawable.ic_bt_headphones_a2dp, level,
                                 iconScale),
                         context.getString(R.string.bluetooth_talkback_headphone));
             }
         }
         return new Pair<>(
-                getBluetoothDrawable(context, R.drawable.ic_settings_bluetooth, level, iconScale),
+                getBluetoothDrawable(context,
+                        com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale),
                 context.getString(R.string.bluetooth_talkback_bluetooth));
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 6b6df9b..a1bf936 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -226,7 +226,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headset_hfp;
+        return com.android.internal.R.drawable.ic_bt_headset_hfp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 77dfbe9..41c1d60 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -228,7 +228,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_hearing_aid;
+        return com.android.internal.R.drawable.ic_bt_hearing_aid;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index c6bb2b3..4bdbc31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -211,7 +211,7 @@
 
     @Override
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headset_hfp;
+        return com.android.internal.R.drawable.ic_bt_headset_hfp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 4dc050c..35600b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -171,7 +171,7 @@
 
     @Override
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_misc_hid;
+        return com.android.internal.R.drawable.ic_bt_misc_hid;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index ca840d9a..7f906f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -165,7 +165,7 @@
 
     public int getDrawableResource(BluetoothClass btClass) {
         if (btClass == null) {
-            return R.drawable.ic_lockscreen_ime;
+            return com.android.internal.R.drawable.ic_lockscreen_ime;
         }
         return getHidClassDrawable(btClass);
     }
@@ -174,11 +174,11 @@
         switch (btClass.getDeviceClass()) {
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
-                return R.drawable.ic_lockscreen_ime;
+                return com.android.internal.R.drawable.ic_lockscreen_ime;
             case BluetoothClass.Device.PERIPHERAL_POINTING:
-                return R.drawable.ic_bt_pointing_hid;
+                return com.android.internal.R.drawable.ic_bt_pointing_hid;
             default:
-                return R.drawable.ic_bt_misc_hid;
+                return com.android.internal.R.drawable.ic_bt_misc_hid;
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 6acdcac..0afc878 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -200,7 +200,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 28975d4..bea944c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -196,7 +196,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 2d0a090..6638592 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -153,7 +153,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_network_pan;
+        return com.android.internal.R.drawable.ic_bt_network_pan;
     }
 
     // Tethering direction determines UI strings.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 4672393..4a27715 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -192,7 +192,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 1b3c453..165af2c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -135,7 +135,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index ea2ebde..9e9c5b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -196,7 +196,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index a5c6f0c..6d0e3ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.util.Log;
 
-import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 /**
@@ -45,7 +44,7 @@
     @Override
     public int getIcon() {
         //TODO(b/117129183): This is not final icon for bluetooth device, just for demo.
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 04f70cc..99d9d1c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -20,8 +20,6 @@
 
 import androidx.mediarouter.media.MediaRouter;
 
-import com.android.settingslib.R;
-
 /**
  * InfoMediaDevice extends MediaDevice to represents wifi device.
  */
@@ -45,7 +43,7 @@
     @Override
     public int getIcon() {
         //TODO(b/121083246): This is not final icon for cast device, just for demo.
-        return R.drawable.ic_settings_print;
+        return com.android.internal.R.drawable.ic_settings_print;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c808214..01003aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.util.Log;
 
-import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -53,7 +52,7 @@
     @Override
     public int getIcon() {
         //TODO(b/117129183): This is not final icon for phone device, just for demo.
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index f02044d..a106846 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -56,7 +56,7 @@
     }
 
     private void init() {
-        setIcon(R.drawable.ic_info_outline_24dp);
+        setIcon(com.android.internal.R.drawable.ic_info_outline_24);
         setKey(KEY_FOOTER);
         setOrder(ORDER_FOOTER);
         setSelectable(false);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
index a436cb5..cf7bcb2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -31,8 +31,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.settingslib.R;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,7 +43,7 @@
     public void getConstantState_shouldNotBeNull() {
         final Bitmap b = BitmapFactory.decodeResource(
                 InstrumentationRegistry.getTargetContext().getResources(),
-                R.drawable.ic_mode_edit);
+                com.android.internal.R.drawable.ic_mode_edit);
         mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
         assertThat(mDrawable.getConstantState()).isNotNull();
     }
diff --git a/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml b/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml
deleted file mode 100644
index 3fe1e9e..0000000
--- a/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorSecondary">
-    <path
-        android:fillColor="#000000"
-        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
-</vector>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 0eb6de9..7a71551 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -20,7 +20,6 @@
 import android.bluetooth.BluetoothDevice;
 import android.graphics.drawable.Drawable;
 
-import com.android.settingslib.R;
 import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 
 import org.junit.Test;
@@ -34,7 +33,7 @@
     @Test
     public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
         final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, R.drawable.ic_bt_laptop,
+                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
                 BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */);
 
         assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
@@ -43,7 +42,7 @@
     @Test
     public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
         final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, R.drawable.ic_bt_laptop,
+                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
                 10 /* batteryLevel */, 1 /* iconScale */);
 
         assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
index b77670b..491f32d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -12,8 +12,6 @@
 import android.content.pm.ActivityInfo;
 import android.os.Bundle;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,7 +29,7 @@
         mActivityInfo = new ActivityInfo();
         mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
         mActivityInfo.name = "abc";
-        mActivityInfo.icon = R.drawable.ic_plus;
+        mActivityInfo.icon = com.android.internal.R.drawable.ic_plus;
         mActivityInfo.metaData = new Bundle();
         mTile = new Tile(mActivityInfo, "category");
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index bbb4249..b379b54 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -53,8 +53,6 @@
 import android.util.ArrayMap;
 import android.util.Pair;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -255,7 +253,7 @@
 
         resolveInfo.activityInfo.metaData = new Bundle(oldMetadata);
         resolveInfo.activityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON,
-                R.drawable.ic_bt_cellphone);
+                com.android.internal.R.drawable.ic_bt_cellphone);
         outTiles.clear();
         TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
index 1b350cc..c6c2a44 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
@@ -31,7 +31,7 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothDeviceLayerDrawableTest {
-    private static final int RES_ID = R.drawable.ic_bt_cellphone;
+    private static final int RES_ID = com.android.internal.R.drawable.ic_bt_cellphone;
     private static final int BATTERY_LEVEL = 15;
     private static final float BATTERY_ICON_SCALE = 0.75f;
     private static final int BATTERY_ICON_PADDING_TOP = 6;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
index 97de7ef..e24b525 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
@@ -74,10 +74,10 @@
 
     @Test
     public void onBindViewHolder_setIcon_shouldShowButtonByDefault() {
-        mPref.setButton1Icon(R.drawable.ic_plus);
-        mPref.setButton2Icon(R.drawable.ic_plus);
-        mPref.setButton3Icon(R.drawable.ic_plus);
-        mPref.setButton4Icon(R.drawable.ic_plus);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton2Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton3Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton4Icon(com.android.internal.R.drawable.ic_plus);
 
         mPref.onBindViewHolder(mHolder);
 
@@ -126,10 +126,10 @@
 
     @Test
     public void onBindViewHolder_setVisibleIsGoneAndSetIcon_shouldNotShowButton() {
-        mPref.setButton1Icon(R.drawable.ic_plus).setButton1Visible(false);
-        mPref.setButton2Icon(R.drawable.ic_plus).setButton2Visible(false);
-        mPref.setButton3Icon(R.drawable.ic_plus).setButton3Visible(false);
-        mPref.setButton4Icon(R.drawable.ic_plus).setButton4Visible(false);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus).setButton1Visible(false);
+        mPref.setButton2Icon(com.android.internal.R.drawable.ic_plus).setButton2Visible(false);
+        mPref.setButton3Icon(com.android.internal.R.drawable.ic_plus).setButton3Visible(false);
+        mPref.setButton4Icon(com.android.internal.R.drawable.ic_plus).setButton4Visible(false);
 
         mPref.onBindViewHolder(mHolder);
 
@@ -215,7 +215,7 @@
     @Test
     public void onBindViewHolder_setButtonIcon_iconMustDisplayAboveText() {
         mPref.setButton1Text(R.string.install_other_apps);
-        mPref.setButton1Icon(R.drawable.ic_plus);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus);
 
         mPref.onBindViewHolder(mHolder);
         final Drawable[] drawablesAroundText =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
index 4c68c14..63a958e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
@@ -54,7 +54,7 @@
         mController = AppEntitiesHeaderController.newInstance(mContext,
                 mAppEntitiesHeaderView);
         mAppEntityInfo = new AppEntityInfo.Builder()
-                .setIcon(mContext.getDrawable(R.drawable.ic_menu))
+                .setIcon(mContext.getDrawable(com.android.internal.R.drawable.ic_menu))
                 .setTitle(TITLE)
                 .setSummary(SUMMARY)
                 .setOnClickListener(v -> {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index cf6137d..c3ea336 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -58,7 +58,7 @@
         mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
         mPreference = new BarChartPreference(mContext, null /* attrs */);
 
-        mIcon = mContext.getDrawable(R.drawable.ic_menu);
+        mIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_menu);
         mBarView1 = mBarChartView.findViewById(R.id.bar_view1);
         mBarView2 = mBarChartView.findViewById(R.id.bar_view2);
         mBarView3 = mBarChartView.findViewById(R.id.bar_view3);
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index abf9e05..67e31ac 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -109,7 +109,7 @@
                 android:contentDescription="@string/accessibility_quick_settings_edit"
                 android:focusable="true"
                 android:padding="15dp"
-                android:src="@drawable/ic_mode_edit"
+                android:src="@*android:drawable/ic_mode_edit"
                 android:tint="?android:attr/colorForeground"/>
 
             <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f14495b..4527f73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,6 +40,7 @@
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricSourceType;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.SoundPool;
 import android.os.Bundle;
@@ -750,7 +751,14 @@
 
         mDeviceInteractive = mPM.isInteractive();
 
-        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
+        mLockSounds = new SoundPool.Builder()
+                .setMaxStreams(1)
+                .setAudioAttributes(
+                        new AudioAttributes.Builder()
+                                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                                .build())
+                .build();
         String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
         if (soundPath != null) {
             mLockSoundId = mLockSounds.load(soundPath, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d740033..a0f4e24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -24,7 +24,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.R.drawable;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
@@ -38,7 +37,7 @@
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
-    private final Icon mIcon = ResourceIcon.get(drawable.ic_signal_location);
+    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_signal_location);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 43ce0b5..de78d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -111,7 +111,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.value = mController.isActivated();
         state.label = mContext.getString(R.string.quick_settings_night_display_label);
-        state.icon = ResourceIcon.get(R.drawable.ic_qs_night_display_on);
+        state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_night_display_on);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.secondaryLabel = getSecondaryLabel(state.value);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c108371..711b08e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -448,6 +448,11 @@
                 false);
         addView(mKeyguardStatusView, index);
 
+        // Re-associate the clock container with the keyguard clock switch.
+        mBigClockContainer.removeAllViews();
+        KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
+        keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+
         // Update keyguard bottom area
         index = indexOfChild(mKeyguardBottomArea);
         removeView(mKeyguardBottomArea);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 844096d..6108aaa 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -177,12 +177,13 @@
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
 
         @Override
-        public void startSession(@UserIdInt int userId, @NonNull IBinder activityToken,
+        public void startSession(@NonNull IBinder activityToken,
                 @NonNull ComponentName componentName, @NonNull String sessionId, int flags,
                 @NonNull IResultReceiver result) {
             Preconditions.checkNotNull(activityToken);
             Preconditions.checkNotNull(componentName);
             Preconditions.checkNotNull(sessionId);
+            final int userId = UserHandle.getCallingUserId();
 
             // TODO(b/111276913): refactor getTaskIdForActivity() to also return ComponentName,
             // so we don't pass it on startSession (same for Autofill)
@@ -199,8 +200,9 @@
         }
 
         @Override
-        public void finishSession(@UserIdInt int userId, @NonNull String sessionId) {
+        public void finishSession(@NonNull String sessionId) {
             Preconditions.checkNotNull(sessionId);
+            final int userId = UserHandle.getCallingUserId();
 
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
@@ -209,15 +211,16 @@
         }
 
         @Override
-        public void getReceiverServiceComponentName(@UserIdInt int userId,
-                IResultReceiver receiver) {
+        public void getServiceComponentName(@NonNull IResultReceiver result) {
+            final int userId = UserHandle.getCallingUserId();
             ComponentName connectedServiceComponentName;
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
                 connectedServiceComponentName = service.getServiceComponentName();
             }
             try {
-                receiver.send(0, SyncResultReceiver.bundleFor(connectedServiceComponentName));
+                result.send(/* resultCode= */ 0,
+                        SyncResultReceiver.bundleFor(connectedServiceComponentName));
             } catch (RemoteException e) {
                 // Ignore exception as we need to be resilient against app behavior.
                 Slog.w(TAG, "Unable to send service component name: " + e);
@@ -225,8 +228,9 @@
         }
 
         @Override
-        public void removeUserData(@UserIdInt int userId, @NonNull UserDataRemovalRequest request) {
+        public void removeUserData(@NonNull UserDataRemovalRequest request) {
             Preconditions.checkNotNull(request);
+            final int userId = UserHandle.getCallingUserId();
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
                 service.removeUserDataLocked(request);
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index dbff957..2756610 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -17,5 +17,15 @@
 package com.android.server;
 
 public interface AlarmManagerInternal {
-    void removeAlarmsForUid(int uid);
+    // Some other components in the system server need to know about
+    // broadcast alarms currently in flight
+    public interface InFlightListener {
+        /** There is now an alarm pending delivery to the given app */
+        void broadcastAlarmPending(int recipientUid);
+        /** A broadcast alarm targeted to the given app has completed delivery */
+        void broadcastAlarmComplete(int recipientUid);
+    }
+
+    public void removeAlarmsForUid(int uid);
+    public void registerInFlightListener(InFlightListener callback);
 }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index e3dcb7d..10b5327 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -197,6 +197,8 @@
     PowerManager.WakeLock mWakeLock;
     ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
     ArrayList<InFlight> mInFlight = new ArrayList<>();
+    private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
+            new ArrayList<>();
     AlarmHandler mHandler;
     AppWakeupHistory mAppWakeupHistory;
     ClockReceiver mClockReceiver;
@@ -1315,6 +1317,10 @@
             mAlarmType = alarm.type;
         }
 
+        boolean isBroadcast() {
+            return mPendingIntent != null && mPendingIntent.isBroadcast();
+        }
+
         @Override
         public String toString() {
             return "InFlight{"
@@ -1354,6 +1360,20 @@
         }
     }
 
+    private void notifyBroadcastAlarmPendingLocked(int uid) {
+        final int numListeners = mInFlightListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            mInFlightListeners.get(i).broadcastAlarmPending(uid);
+        }
+    }
+
+    private void notifyBroadcastAlarmCompleteLocked(int uid) {
+        final int numListeners = mInFlightListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            mInFlightListeners.get(i).broadcastAlarmComplete(uid);
+        }
+    }
+
     static final class FilterStats {
         final BroadcastStats mBroadcastStats;
         final String mTag;
@@ -1976,6 +1996,13 @@
                 removeLocked(uid);
             }
         }
+
+        @Override
+        public void registerInFlightListener(InFlightListener callback) {
+            synchronized (mLock) {
+                mInFlightListeners.add(callback);
+            }
+        }
     }
 
     /**
@@ -4426,7 +4453,11 @@
 
         private InFlight removeLocked(PendingIntent pi, Intent intent) {
             for (int i = 0; i < mInFlight.size(); i++) {
-                if (mInFlight.get(i).mPendingIntent == pi) {
+                final InFlight inflight = mInFlight.get(i);
+                if (inflight.mPendingIntent == pi) {
+                    if (pi.isBroadcast()) {
+                        notifyBroadcastAlarmCompleteLocked(inflight.mUid);
+                    }
                     return mInFlight.remove(i);
                 }
             }
@@ -4649,6 +4680,9 @@
             final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED);
             mInFlight.add(inflight);
             mBroadcastRefCount++;
+            if (inflight.isBroadcast()) {
+                notifyBroadcastAlarmPendingLocked(alarm.uid);
+            }
             if (allowWhileIdle) {
                 // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
                 mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cec825f..cecd55a3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -802,10 +802,7 @@
         // For now, simply clone property when it changes
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE,
                 mContext.getMainExecutor(), (namespace, name, value) -> {
-                    if (DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED.equals(name)) {
-                        Settings.Global.putString(mResolver,
-                                Settings.Global.ISOLATED_STORAGE_REMOTE, value);
-                    }
+                    refreshIsolatedStorageSettings();
                 });
         refreshIsolatedStorageSettings();
     }
@@ -840,6 +837,12 @@
     }
 
     private void refreshIsolatedStorageSettings() {
+        // Always copy value from newer DeviceConfig location
+        Settings.Global.putString(mResolver,
+                Settings.Global.ISOLATED_STORAGE_REMOTE,
+                DeviceConfig.getProperty(DeviceConfig.Storage.NAMESPACE,
+                        DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED));
+
         final int local = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
         final int remote = Settings.Global.getInt(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 0aaea2f..e42666c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -48,6 +48,7 @@
     static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false;
     static final boolean DEBUG_LRU = DEBUG_ALL || false;
     static final boolean DEBUG_MU = DEBUG_ALL || false;
     static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index eb643b6..d9f3c02 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -224,7 +224,6 @@
 import android.location.LocationManager;
 import android.media.audiofx.AudioEffect;
 import android.net.Proxy;
-import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.AppZygote;
 import android.os.BatteryStats;
@@ -2090,6 +2089,8 @@
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
                 mService.mBatteryStatsService.systemServicesReady();
                 mService.mServices.systemServicesReady();
+            } else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+                mService.startBroadcastObservers();
             }
         }
 
@@ -2266,12 +2267,27 @@
         mProcessList.init(this, activeUids);
         mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
 
+        // Broadcast policy parameters
+        final BroadcastConstants foreConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_FG_CONSTANTS);
+        foreConstants.TIMEOUT = BROADCAST_FG_TIMEOUT;
+
+        final BroadcastConstants backConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_BG_CONSTANTS);
+        backConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
+
+        final BroadcastConstants offloadConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_OFFLOAD_CONSTANTS);
+        offloadConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
+        // by default, no "slow" policy in this queue
+        offloadConstants.SLOW_TIME = Integer.MAX_VALUE;
+
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "foreground", BROADCAST_FG_TIMEOUT, false);
+                "foreground", foreConstants, false);
         mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "background", BROADCAST_BG_TIMEOUT, true);
+                "background", backConstants, true);
         mOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "offload", BROADCAST_BG_TIMEOUT, true);
+                "offload", offloadConstants, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
         mBroadcastQueues[2] = mOffloadBroadcastQueue;
@@ -5226,6 +5242,15 @@
     }
 
     @Override
+    public boolean isIntentSenderABroadcast(IIntentSender pendingResult) {
+        if (pendingResult instanceof PendingIntentRecord) {
+            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
+            return res.key.type == ActivityManager.INTENT_SENDER_BROADCAST;
+        }
+        return false;
+    }
+
+    @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
         enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
                 "getIntentForIntentSender()");
@@ -7211,7 +7236,6 @@
         synchronized (this) {
             mSystemProvidersInstalled = true;
         }
-
         mConstants.start(mContext.getContentResolver());
         mCoreSettingsObserver = new CoreSettingsObserver(this);
         mActivityTaskManager.installSystemProviders();
@@ -8711,6 +8735,12 @@
         }
     }
 
+    private void startBroadcastObservers() {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.start(mContext.getContentResolver());
+        }
+    }
+
     private void updateForceBackgroundCheck(boolean enabled) {
         synchronized (this) {
             if (mForceBackgroundCheck != enabled) {
@@ -14909,10 +14939,7 @@
                     resultData, resultExtras, ordered, sticky, false, userId,
                     allowBackgroundActivityStarts);
 
-            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
-                    + ": prev had " + queue.mOrderedBroadcasts.size());
-            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
-                    "Enqueueing broadcast " + r.intent.getAction());
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
 
             final BroadcastRecord oldRecord =
                     replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
@@ -15788,13 +15815,12 @@
      * Returns true if things are idle enough to perform GCs.
      */
     private final boolean canGcNowLocked() {
-        boolean processingBroadcasts = false;
         for (BroadcastQueue q : mBroadcastQueues) {
-            if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) {
-                processingBroadcasts = true;
+            if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isEmpty()) {
+                return false;
             }
         }
-        return !processingBroadcasts && mAtmInternal.canGcNow();
+        return mAtmInternal.canGcNow();
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
new file mode 100644
index 0000000..820caf1
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
+
+/**
+ * Tunable parameters for broadcast dispatch policy
+ */
+public class BroadcastConstants {
+    private static final String TAG = "BroadcastConstants";
+
+    // Value element names within the Settings record
+    static final String KEY_TIMEOUT = "bcast_timeout";
+    static final String KEY_SLOW_TIME = "bcast_slow_time";
+    static final String KEY_DEFERRAL = "bcast_deferral";
+    static final String KEY_DEFERRAL_DECAY_FACTOR = "bcast_deferral_decay_factor";
+    static final String KEY_DEFERRAL_FLOOR = "bcast_deferral_floor";
+
+    // All time intervals are in milliseconds
+    private static final long DEFAULT_TIMEOUT = 10_000;
+    private static final long DEFAULT_SLOW_TIME = 5_000;
+    private static final long DEFAULT_DEFERRAL = 5_000;
+    private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
+    private static final long DEFAULT_DEFERRAL_FLOOR = 0;
+
+    // All time constants are in milliseconds
+
+    // Timeout period for this broadcast queue
+    public long TIMEOUT = DEFAULT_TIMEOUT;
+    // Handling time above which we declare that a broadcast recipient was "slow".  Any
+    // value <= zero is interpreted as disabling broadcast deferral policy entirely.
+    public long SLOW_TIME = DEFAULT_SLOW_TIME;
+    // How long to initially defer broadcasts, if an app is slow to handle one
+    public long DEFERRAL = DEFAULT_DEFERRAL;
+    // Decay factor for successive broadcasts' deferral time
+    public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR;
+    // Minimum that the deferral time can decay to until the backlog fully clears
+    public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR;
+
+    // Settings override tracking for this instance
+    private String mSettingsKey;
+    private SettingsObserver mSettingsObserver;
+    private ContentResolver mResolver;
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            updateConstants();
+        }
+    }
+
+    // A given constants instance is configured to observe specific keys from which
+    // that instance's values are drawn.
+    public BroadcastConstants(String settingsKey) {
+        mSettingsKey = settingsKey;
+    }
+
+    /**
+     * Spin up the observer lazily, since it can only happen once the settings provider
+     * has been brought into service
+     */
+    public void startObserving(Handler handler, ContentResolver resolver) {
+        mResolver = resolver;
+
+        mSettingsObserver = new SettingsObserver(handler);
+        mResolver.registerContentObserver(Settings.Global.getUriFor(mSettingsKey),
+                false, mSettingsObserver);
+
+        updateConstants();
+    }
+
+    private void updateConstants() {
+        synchronized (mParser) {
+            try {
+                mParser.setString(Settings.Global.getString(mResolver, mSettingsKey));
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Bad broadcast settings in key '" + mSettingsKey + "'", e);
+                return;
+            }
+
+            // Unspecified fields retain their current value rather than revert to default
+            TIMEOUT = mParser.getLong(KEY_TIMEOUT, TIMEOUT);
+            SLOW_TIME = mParser.getLong(KEY_SLOW_TIME, SLOW_TIME);
+            DEFERRAL = mParser.getLong(KEY_DEFERRAL, DEFERRAL);
+            DEFERRAL_DECAY_FACTOR = mParser.getFloat(KEY_DEFERRAL_DECAY_FACTOR,
+                    DEFERRAL_DECAY_FACTOR);
+            DEFERRAL_FLOOR = mParser.getLong(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR);
+        }
+    }
+
+    /**
+     * Standard dumpsys support; invoked from BroadcastQueue dump
+     */
+    public void dump(PrintWriter pw) {
+        synchronized (mParser) {
+            pw.println();
+            pw.print("  Broadcast parameters (key=");
+            pw.print(mSettingsKey);
+            pw.print(", observing=");
+            pw.print(mSettingsObserver != null);
+            pw.println("):");
+
+            pw.print("    "); pw.print(KEY_TIMEOUT); pw.print(" = ");
+            TimeUtils.formatDuration(TIMEOUT, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_SLOW_TIME); pw.print(" = ");
+            TimeUtils.formatDuration(SLOW_TIME, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_DEFERRAL); pw.print(" = ");
+            TimeUtils.formatDuration(DEFERRAL, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_DEFERRAL_DECAY_FACTOR); pw.print(" = ");
+            pw.println(DEFERRAL_DECAY_FACTOR);
+
+            pw.print("    "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = ");
+            TimeUtils.formatDuration(DEFERRAL_FLOOR, pw);
+            pw.println();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
new file mode 100644
index 0000000..0d46379
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.AlarmManagerInternal;
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Manages ordered broadcast delivery, applying policy to mitigate the effects of
+ * slow receivers.
+ */
+public class BroadcastDispatcher {
+    private static final String TAG = "BroadcastDispatcher";
+
+    // Deferred broadcasts to one app; times are all uptime time base like
+    // other broadcast-related timekeeping
+    static class Deferrals {
+        final int uid;
+        long deferredAt;    // when we started deferring
+        long deferredBy;    // how long did we defer by last time?
+        long deferUntil;    // when does the next element become deliverable?
+        int alarmCount;
+
+        final ArrayList<BroadcastRecord> broadcasts;
+
+        Deferrals(int uid, long now, long backoff, int count) {
+            this.uid = uid;
+            this.deferredAt = now;
+            this.deferredBy = backoff;
+            this.deferUntil = now + backoff;
+            this.alarmCount = count;
+            broadcasts = new ArrayList<>();
+        }
+
+        void add(BroadcastRecord br) {
+            broadcasts.add(br);
+        }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            for (BroadcastRecord br : broadcasts) {
+                br.writeToProto(proto, fieldId);
+            }
+        }
+
+        void dumpLocked(Dumper d) {
+            for (BroadcastRecord br : broadcasts) {
+                d.dump(br);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Deferrals{uid=");
+            sb.append(uid);
+            sb.append(", deferUntil=");
+            sb.append(deferUntil);
+            sb.append(", #broadcasts=");
+            sb.append(broadcasts.size());
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+    // Carrying dump formatting state across multiple concatenated datasets
+    class Dumper {
+        final PrintWriter mPw;
+        final String mQueueName;
+        final String mDumpPackage;
+        final SimpleDateFormat mSdf;
+        boolean mPrinted;
+        boolean mNeedSep;
+        String mHeading;
+        String mLabel;
+        int mOrdinal;
+
+        Dumper(PrintWriter pw, String queueName, String dumpPackage, SimpleDateFormat sdf) {
+            mPw = pw;
+            mQueueName = queueName;
+            mDumpPackage = dumpPackage;
+            mSdf = sdf;
+
+            mPrinted = false;
+            mNeedSep = true;
+        }
+
+        void setHeading(String heading) {
+            mHeading = heading;
+            mPrinted = false;
+        }
+
+        void setLabel(String label) {
+            //"  Active Ordered Broadcast " + mQueueName + " #" + i + ":"
+            mLabel = "  " + label + " " + mQueueName + " #";
+            mOrdinal = 0;
+        }
+
+        boolean didPrint() {
+            return mPrinted;
+        }
+
+        void dump(BroadcastRecord br) {
+            if (mDumpPackage == null || mDumpPackage.equals(br.callerPackage)) {
+                if (!mPrinted) {
+                    if (mNeedSep) {
+                        mPw.println();
+                    }
+                    mPrinted = true;
+                    mNeedSep = true;
+                    mPw.println("  " + mHeading + " [" + mQueueName + "]:");
+                }
+                mPw.println(mLabel + mOrdinal + ":");
+                mOrdinal++;
+
+                br.dump(mPw, "    ", mSdf);
+            }
+        }
+    }
+
+    private final Object mLock;
+    private final BroadcastQueue mQueue;
+    private final BroadcastConstants mConstants;
+    private final Handler mHandler;
+    private AlarmManagerInternal mAlarm;
+
+    // Current alarm targets; mapping uid -> in-flight alarm count
+    final SparseIntArray mAlarmUids = new SparseIntArray();
+    final AlarmManagerInternal.InFlightListener mAlarmListener =
+            new AlarmManagerInternal.InFlightListener() {
+        @Override
+        public void broadcastAlarmPending(final int recipientUid) {
+            synchronized (mLock) {
+                final int newCount = mAlarmUids.get(recipientUid, 0) + 1;
+                mAlarmUids.put(recipientUid, newCount);
+                // any deferred broadcasts to this app now get fast-tracked
+                final int numEntries = mDeferredBroadcasts.size();
+                for (int i = 0; i < numEntries; i++) {
+                    if (recipientUid == mDeferredBroadcasts.get(i).uid) {
+                        Deferrals d = mDeferredBroadcasts.remove(i);
+                        mAlarmBroadcasts.add(d);
+                        break;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void broadcastAlarmComplete(final int recipientUid) {
+            synchronized (mLock) {
+                final int newCount = mAlarmUids.get(recipientUid, 0) - 1;
+                if (newCount >= 0) {
+                    mAlarmUids.put(recipientUid, newCount);
+                } else {
+                    Slog.wtf(TAG, "Undercount of broadcast alarms in flight for " + recipientUid);
+                    mAlarmUids.put(recipientUid, 0);
+                }
+
+                // No longer an alarm target, so resume ordinary deferral policy
+                if (newCount <= 0) {
+                    final int numEntries = mAlarmBroadcasts.size();
+                    for (int i = 0; i < numEntries; i++) {
+                        if (recipientUid == mAlarmBroadcasts.get(i).uid) {
+                            Deferrals d = mAlarmBroadcasts.remove(i);
+                            insertLocked(mDeferredBroadcasts, d);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    // Queue recheck operation used to tickle broadcast delivery when appropriate
+    final Runnable mScheduleRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.v(TAG, "Deferral recheck of pending broadcasts");
+                }
+                mQueue.scheduleBroadcastsLocked();
+                mRecheckScheduled = false;
+            }
+        }
+    };
+    private boolean mRecheckScheduled = false;
+
+    // Usual issuance-order outbound queue
+    private final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
+    // General deferrals not holding up alarms
+    private final ArrayList<Deferrals> mDeferredBroadcasts = new ArrayList<>();
+    // Deferrals that *are* holding up alarms; ordered by alarm dispatch time
+    private final ArrayList<Deferrals> mAlarmBroadcasts = new ArrayList<>();
+
+    // Next outbound broadcast, established by getNextBroadcastLocked()
+    private BroadcastRecord mCurrentBroadcast;
+
+    /**
+     * Constructed & sharing a lock with its associated BroadcastQueue instance
+     */
+    public BroadcastDispatcher(BroadcastQueue queue, BroadcastConstants constants,
+            Handler handler, Object lock) {
+        mQueue = queue;
+        mConstants = constants;
+        mHandler = handler;
+        mLock = lock;
+    }
+
+    /**
+     * Spin up the integration with the alarm manager service; done lazily to manage
+     * service availability ordering during boot.
+     */
+    public void start() {
+        // Set up broadcast alarm tracking
+        mAlarm = LocalServices.getService(AlarmManagerInternal.class);
+        mAlarm.registerInFlightListener(mAlarmListener);
+    }
+
+    /**
+     * Standard contents-are-empty check
+     */
+    public boolean isEmpty() {
+        synchronized (mLock) {
+            return mCurrentBroadcast == null
+                    && mOrderedBroadcasts.isEmpty()
+                    && mDeferredBroadcasts.isEmpty()
+                    && mAlarmBroadcasts.isEmpty();
+        }
+    }
+
+    /**
+     * Not quite the traditional size() measurement; includes any in-process but
+     * not yet retired active outbound broadcast.
+     */
+    public int totalUndelivered() {
+        synchronized (mLock) {
+            return mAlarmBroadcasts.size()
+                    + mDeferredBroadcasts.size()
+                    + mOrderedBroadcasts.size()
+                    + (mCurrentBroadcast == null ? 0 : 1);
+        }
+    }
+
+    // ----------------------------------
+    // BroadcastQueue operation support
+
+    void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+        mOrderedBroadcasts.add(r);
+    }
+
+    // Returns the now-replaced broadcast record, or null if none
+    BroadcastRecord replaceBroadcastLocked(BroadcastRecord r, String typeForLogging) {
+        // Simple case, in the ordinary queue.
+        BroadcastRecord old = replaceBroadcastLocked(mOrderedBroadcasts, r, typeForLogging);
+
+        // If we didn't find it, less-simple:  in a deferral queue?
+        if (old == null) {
+            old = replaceDeferredBroadcastLocked(mAlarmBroadcasts, r, typeForLogging);
+        }
+        if (old == null) {
+            old = replaceDeferredBroadcastLocked(mDeferredBroadcasts, r, typeForLogging);
+        }
+        return old;
+    }
+
+    private BroadcastRecord replaceDeferredBroadcastLocked(ArrayList<Deferrals> list,
+            BroadcastRecord r, String typeForLogging) {
+        BroadcastRecord old;
+        final int numEntries = list.size();
+        for (int i = 0; i < numEntries; i++) {
+            final Deferrals d = list.get(i);
+            old = replaceBroadcastLocked(d.broadcasts, r, typeForLogging);
+            if (old != null) {
+                return old;
+            }
+        }
+        return null;
+    }
+
+    private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> list,
+            BroadcastRecord r, String typeForLogging) {
+        BroadcastRecord old;
+        final Intent intent = r.intent;
+        // Any in-flight broadcast has already been popped, and cannot be replaced.
+        // (This preserves existing behavior of the replacement API)
+        for (int i = list.size() - 1; i >= 0; i++) {
+            old = list.get(i);
+            if (old.userId == r.userId && intent.filterEquals(old.intent)) {
+                if (DEBUG_BROADCAST) {
+                    Slog.v(TAG, "***** Replacing " + typeForLogging
+                            + " [" + mQueue.mQueueName + "]: " + intent);
+                }
+                // Clone deferral state too if any
+                r.deferred = old.deferred;
+                list.set(i, r);
+                return old;
+            }
+        }
+        return null;
+    }
+
+    boolean cleanupDisabledPackageReceiversLocked(final String packageName,
+            Set<String> filterByClasses, final int userId, final boolean doit) {
+        // Note: fast short circuits when 'doit' is false, as soon as we hit any
+        // "yes we would do something" circumstance
+        boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
+                packageName, filterByClasses, userId, doit);
+        if (doit || !didSomething) {
+            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
+                    packageName, filterByClasses, userId, doit);
+        }
+        if (doit || !didSomething) {
+            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mDeferredBroadcasts,
+                    packageName, filterByClasses, userId, doit);
+        }
+        if ((doit || !didSomething) && mCurrentBroadcast != null) {
+            didSomething |= mCurrentBroadcast.cleanupDisabledPackageReceiversLocked(
+                    packageName, filterByClasses, userId, doit);
+        }
+
+        return didSomething;
+    }
+
+    private boolean cleanupDeferralsListDisabledReceiversLocked(ArrayList<Deferrals> list,
+            final String packageName, Set<String> filterByClasses, final int userId,
+            final boolean doit) {
+        boolean didSomething = false;
+        for (Deferrals d : list) {
+            didSomething = cleanupBroadcastListDisabledReceiversLocked(d.broadcasts,
+                    packageName, filterByClasses, userId, doit);
+            if (!doit && didSomething) {
+                return true;
+            }
+        }
+        return didSomething;
+    }
+
+    private boolean cleanupBroadcastListDisabledReceiversLocked(ArrayList<BroadcastRecord> list,
+            final String packageName, Set<String> filterByClasses, final int userId,
+            final boolean doit) {
+        boolean didSomething = false;
+        for (BroadcastRecord br : list) {
+            didSomething |= br.cleanupDisabledPackageReceiversLocked(packageName,
+                    filterByClasses, userId, doit);
+            if (!doit && didSomething) {
+                return true;
+            }
+        }
+        return didSomething;
+    }
+
+    /**
+     * Standard proto dump entry point
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        if (mCurrentBroadcast != null) {
+            mCurrentBroadcast.writeToProto(proto, fieldId);
+        }
+        for (Deferrals d : mAlarmBroadcasts) {
+            d.writeToProto(proto, fieldId);
+        }
+        for (BroadcastRecord br : mOrderedBroadcasts) {
+            br.writeToProto(proto, fieldId);
+        }
+        for (Deferrals d : mDeferredBroadcasts) {
+            d.writeToProto(proto, fieldId);
+        }
+    }
+
+    // ----------------------------------
+    // Dispatch & deferral management
+
+    public BroadcastRecord getActiveBroadcastLocked() {
+        return mCurrentBroadcast;
+    }
+
+    /**
+     * If there is a deferred broadcast that is being sent to an alarm target, return
+     * that one.  If there's no deferred alarm target broadcast but there is one
+     * that has reached the end of its deferral, return that.
+     *
+     * This stages the broadcast internally until it is retired, and returns that
+     * staged record if this is called repeatedly, until retireBroadcast(r) is called.
+     */
+    public BroadcastRecord getNextBroadcastLocked(final long now) {
+        if (mCurrentBroadcast != null) {
+            return mCurrentBroadcast;
+        }
+
+        BroadcastRecord next = null;
+        if (!mAlarmBroadcasts.isEmpty()) {
+            next = popLocked(mAlarmBroadcasts);
+            if (DEBUG_BROADCAST_DEFERRAL && next != null) {
+                Slog.i(TAG, "Next broadcast from alarm targets: " + next);
+            }
+        }
+
+        if (next == null && !mDeferredBroadcasts.isEmpty()) {
+            for (int i = 0; i < mDeferredBroadcasts.size(); i++) {
+                Deferrals d = mDeferredBroadcasts.get(i);
+                if (now < d.deferUntil) {
+                    // No more deferrals due
+                    break;
+                }
+
+                if (d.broadcasts.size() > 0) {
+                    next = d.broadcasts.remove(0);
+                    // apply deferral-interval decay policy and move this uid's
+                    // deferred broadcasts down in the delivery queue accordingly
+                    mDeferredBroadcasts.remove(i); // already 'd'
+                    d.deferredBy = calculateDeferral(d.deferredBy);
+                    d.deferUntil += d.deferredBy;
+                    insertLocked(mDeferredBroadcasts, d);
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG, "Next broadcast from deferrals " + next
+                                + ", deferUntil now " + d.deferUntil);
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (next == null && !mOrderedBroadcasts.isEmpty()) {
+            next = mOrderedBroadcasts.remove(0);
+            if (DEBUG_BROADCAST_DEFERRAL) {
+                Slog.i(TAG, "Next broadcast from main queue: " + next);
+            }
+        }
+
+        mCurrentBroadcast = next;
+        return next;
+    }
+
+    /**
+     * Called after the broadcast queue finishes processing the currently
+     * active broadcast (obtained by calling getNextBroadcastLocked()).
+     */
+    public void retireBroadcastLocked(final BroadcastRecord r) {
+        // ERROR if 'r' is not the active broadcast
+        if (r != mCurrentBroadcast) {
+            Slog.wtf(TAG, "Retiring broadcast " + r
+                    + " doesn't match current outgoing " + mCurrentBroadcast);
+        }
+        mCurrentBroadcast = null;
+    }
+
+    /**
+     * Called prior to broadcast dispatch to check whether the intended
+     * recipient is currently subject to deferral policy.
+     */
+    public boolean isDeferringLocked(final int uid) {
+        Deferrals d = findUidLocked(uid);
+        if (d != null && d.broadcasts.isEmpty()) {
+            // once we've caught up with deferred broadcasts to this uid
+            // and time has advanced sufficiently that we wouldn't be
+            // deferring newly-enqueued ones, we're back to normal policy.
+            if (SystemClock.uptimeMillis() >= d.deferUntil) {
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "No longer deferring broadcasts to uid " + d.uid);
+                }
+                removeDeferral(d);
+                return false;
+            }
+        }
+        return (d != null);
+    }
+
+    /**
+     * Defer broadcasts for the given app.  If 'br' is non-null, this also makes
+     * sure that broadcast record is enqueued as the next upcoming broadcast for
+     * the app.
+     */
+    public void startDeferring(final int uid) {
+        synchronized (mLock) {
+            Deferrals d = findUidLocked(uid);
+
+            // If we're not yet tracking this app, set up that bookkeeping
+            if (d == null) {
+                // Start a new deferral
+                final long now = SystemClock.uptimeMillis();
+                d = new Deferrals(uid,
+                        now,
+                        mConstants.DEFERRAL,
+                        mAlarmUids.get(uid, 0));
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Now deferring broadcasts to " + uid
+                            + " until " + d.deferUntil);
+                }
+                // where it goes depends on whether it is coming into an alarm-related situation
+                if (d.alarmCount == 0) {
+                    // common case, put it in the ordinary priority queue
+                    insertLocked(mDeferredBroadcasts, d);
+                    scheduleDeferralCheckLocked(true);
+                } else {
+                    // alarm-related: strict order-encountered
+                    mAlarmBroadcasts.add(d);
+                }
+            } else {
+                // We're already deferring, but something was slow again.  Reset the
+                // deferral decay progression.
+                d.deferredBy = mConstants.DEFERRAL;
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Uid " + uid + " slow again, deferral interval reset to "
+                            + d.deferredBy);
+                }
+            }
+        }
+    }
+
+    /**
+     * Key entry point when a broadcast about to be delivered is instead
+     * set aside for deferred delivery
+     */
+    public void addDeferredBroadcast(final int uid, BroadcastRecord br) {
+        if (DEBUG_BROADCAST_DEFERRAL) {
+            Slog.i(TAG, "Enqueuing deferred broadcast " + br);
+        }
+        synchronized (mLock) {
+            Deferrals d = findUidLocked(uid);
+            if (d == null) {
+                Slog.wtf(TAG, "Adding deferred broadcast but not tracking " + uid);
+            } else {
+                if (br == null) {
+                    Slog.wtf(TAG, "Deferring null broadcast to " + uid);
+                } else {
+                    br.deferred = true;
+                    d.add(br);
+                }
+            }
+        }
+    }
+
+    /**
+     * When there are deferred broadcasts, we need to make sure to recheck the
+     * dispatch queue when they come due.  Alarm-sensitive deferrals get dispatched
+     * aggressively, so we only need to use the ordinary deferrals timing to figure
+     * out when to recheck.
+     */
+    public void scheduleDeferralCheckLocked(boolean force) {
+        if ((force || !mRecheckScheduled) && !mDeferredBroadcasts.isEmpty()) {
+            final Deferrals d = mDeferredBroadcasts.get(0);
+            if (!d.broadcasts.isEmpty()) {
+                mHandler.removeCallbacks(mScheduleRunnable);
+                mHandler.postAtTime(mScheduleRunnable, d.deferUntil);
+                mRecheckScheduled = true;
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Scheduling deferred broadcast recheck at " + d.deferUntil);
+                }
+            }
+        }
+    }
+
+    // ----------------------------------
+
+    /**
+     * If broadcasts to this uid are being deferred, find the deferrals record about it.
+     * @return null if this uid's broadcasts are not being deferred
+     */
+    private Deferrals findUidLocked(final int uid) {
+        // The common case is that they it isn't also an alarm target...
+        Deferrals d = findUidLocked(uid, mDeferredBroadcasts);
+        // ...but if not there, also check alarm-prioritized deferrals
+        if (d == null) {
+            d = findUidLocked(uid, mAlarmBroadcasts);
+        }
+        return d;
+    }
+
+    /**
+     * Remove the given deferral record from whichever queue it might be in at present
+     * @return true if the deferral was in fact found, false if this made no changes
+     */
+    private boolean removeDeferral(Deferrals d) {
+        boolean didRemove = mDeferredBroadcasts.remove(d);
+        if (!didRemove) {
+            didRemove = mAlarmBroadcasts.remove(d);
+        }
+        return didRemove;
+    }
+
+    /**
+     * Find the deferrals record for the given uid in the given list
+     */
+    private static Deferrals findUidLocked(final int uid, ArrayList<Deferrals> list) {
+        final int numElements = list.size();
+        for (int i = 0; i < numElements; i++) {
+            Deferrals d = list.get(i);
+            if (uid == d.uid) {
+                return d;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Pop the next broadcast record from the head of the given deferrals list,
+     * if one exists.
+     */
+    private static BroadcastRecord popLocked(ArrayList<Deferrals> list) {
+        final Deferrals d = list.get(0);
+        return d.broadcasts.isEmpty() ? null : d.broadcasts.remove(0);
+    }
+
+    /**
+     * Insert the given Deferrals into the priority queue, sorted by defer-until milestone
+     */
+    private static void insertLocked(ArrayList<Deferrals> list, Deferrals d) {
+        // Simple linear search is appropriate here because we expect to
+        // have very few entries in the deferral lists (i.e. very few badly-
+        // behaving apps currently facing deferral)
+        int i;
+        final int numElements = list.size();
+        for (i = 0; i < numElements; i++) {
+            if (d.deferUntil < list.get(i).deferUntil) {
+                break;
+            }
+        }
+        list.add(i, d);
+    }
+
+    /**
+     * Calculate a new deferral time based on the previous time.  This should decay
+     * toward zero, though a small nonzero floor is an option.
+     */
+    private long calculateDeferral(long previous) {
+        return Math.max(mConstants.DEFERRAL_FLOOR,
+                (long) (previous * mConstants.DEFERRAL_DECAY_FACTOR));
+    }
+
+    // ----------------------------------
+
+    boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
+            SimpleDateFormat sdf) {
+        final Dumper dumper = new Dumper(pw, queueName, dumpPackage, sdf);
+        boolean printed = false;
+
+        dumper.setHeading("Active ordered broadcasts");
+        dumper.setLabel("Active Ordered Broadcast");
+        for (Deferrals d : mAlarmBroadcasts) {
+            d.dumpLocked(dumper);
+        }
+        printed |= dumper.didPrint();
+
+        for (BroadcastRecord br : mOrderedBroadcasts) {
+            dumper.dump(br);
+        }
+        printed |= dumper.didPrint();
+
+        dumper.setHeading("Deferred ordered broadcasts");
+        dumper.setLabel("Deferred Ordered Broadcast");
+        for (Deferrals d : mDeferredBroadcasts) {
+            d.dumpLocked(dumper);
+        }
+        printed |= dumper.didPrint();
+
+        return printed;
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index cdf6e0e..64a36ef 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -24,6 +24,7 @@
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -45,6 +46,7 @@
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -75,16 +77,17 @@
     final ActivityManagerService mService;
 
     /**
+     * Behavioral parameters such as timeouts and deferral policy, tracking Settings
+     * for runtime configurability
+     */
+    final BroadcastConstants mConstants;
+
+    /**
      * Recognizable moniker for this queue
      */
     final String mQueueName;
 
     /**
-     * Timeout period for this queue's broadcasts
-     */
-    final long mTimeoutPeriod;
-
-    /**
      * If true, we can delay broadcasts while waiting services to finish in the previous
      * receiver's process.
      */
@@ -100,13 +103,18 @@
     final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
 
     /**
-     * List of all active broadcasts that are to be executed one at a time.
-     * The object at the top of the list is the currently activity broadcasts;
-     * those after it are waiting for the top to finish.  As with parallel
-     * broadcasts, separate background- and foreground-priority queues are
-     * maintained.
+     * Tracking of the ordered broadcast queue, including deferral policy and alarm
+     * prioritization.
      */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
+    final BroadcastDispatcher mDispatcher;
+
+    /**
+     * Refcounting for completion callbacks of split/deferred broadcasts.  The key
+     * is an opaque integer token assigned lazily when a broadcast is first split
+     * into multiple BroadcastRecord objects.
+     */
+    final SparseIntArray mSplitRefcounts = new SparseIntArray();
+    private int mNextToken = 0;
 
     /**
      * Historical data of past broadcasts, for debugging.  This is a ring buffer
@@ -173,7 +181,8 @@
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
                     if (DEBUG_BROADCAST) Slog.v(
-                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
+                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+                            + mQueueName + "]");
                     processNextBroadcast(true);
                 } break;
                 case BROADCAST_TIMEOUT_MSG: {
@@ -201,12 +210,19 @@
     }
 
     BroadcastQueue(ActivityManagerService service, Handler handler,
-            String name, long timeoutPeriod, boolean allowDelayBehindServices) {
+            String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
         mService = service;
         mHandler = new BroadcastHandler(handler.getLooper());
         mQueueName = name;
-        mTimeoutPeriod = timeoutPeriod;
         mDelayBehindServices = allowDelayBehindServices;
+
+        mConstants = constants;
+        mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
+    }
+
+    void start(ContentResolver resolver) {
+        mDispatcher.start();
+        mConstants.startObserving(mHandler, resolver);
     }
 
     @Override
@@ -224,7 +240,7 @@
     }
 
     public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
-        mOrderedBroadcasts.add(r);
+        mDispatcher.enqueueOrderedBroadcastLocked(r);
         enqueueBroadcastHelper(r);
     }
 
@@ -255,7 +271,7 @@
      * the old one.
      */
     public final BroadcastRecord replaceOrderedBroadcastLocked(BroadcastRecord r) {
-        return replaceBroadcastLocked(mOrderedBroadcasts, r, "ORDERED");
+        return mDispatcher.replaceBroadcastLocked(r, "ORDERED");
     }
 
     private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> queue,
@@ -365,14 +381,17 @@
         }
     }
 
+    // Skip the current receiver, if any, that is in flight to the given process
     public void skipCurrentReceiverLocked(ProcessRecord app) {
         BroadcastRecord r = null;
-        if (mOrderedBroadcasts.size() > 0) {
-            BroadcastRecord br = mOrderedBroadcasts.get(0);
-            if (br.curApp == app) {
-                r = br;
-            }
+        final BroadcastRecord curActive = mDispatcher.getActiveBroadcastLocked();
+        if (curActive != null && curActive.curApp == app) {
+            // confirmed: the current active broadcast is to the given app
+            r = curActive;
         }
+
+        // If the current active broadcast isn't this BUT we're waiting for
+        // mPendingBroadcast to spin up the target app, that's what we use.
         if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "[" + mQueueName + "] skip & discard pending app " + r);
@@ -404,20 +423,29 @@
     }
 
     public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
-        if (mOrderedBroadcasts.size() > 0) {
-            final BroadcastRecord r = mOrderedBroadcasts.get(0);
-            if (r != null && r.receiver == receiver) {
-                return r;
-            }
+        BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
+        if (br != null && br.receiver == receiver) {
+            return br;
         }
         return null;
     }
 
+    // > 0 only, no worry about "eventual" recycling
+    private int nextSplitTokenLocked() {
+        int next = mNextToken + 1;
+        if (next <= 0) {
+            next = 1;
+        }
+        mNextToken = next;
+        return next;
+    }
+
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
             String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
         final int state = r.state;
         final ActivityInfo receiver = r.curReceiver;
         final long finishTime = SystemClock.uptimeMillis();
+        final long elapsed = finishTime - r.receiverTime;
         r.state = BroadcastRecord.IDLE;
         if (state == BroadcastRecord.IDLE) {
             Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
@@ -428,8 +456,22 @@
         // If we're abandoning this broadcast before any receivers were actually spun up,
         // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
         if (r.nextReceiver > 0) {
-            r.duration[r.nextReceiver - 1] = finishTime - r.receiverTime;
+            r.duration[r.nextReceiver - 1] = elapsed;
         }
+
+        // if this receiver was slow, impose deferral policy on the app.  This will kick in
+        // when processNextBroadcastLocked() next finds this uid as a receiver identity.
+        if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+            if (DEBUG_BROADCAST_DEFERRAL) {
+                Slog.i(TAG, "Broadcast receiver was slow: " + receiver + " br=" + r);
+            }
+            if (r.curApp != null) {
+                mDispatcher.startDeferring(r.curApp.uid);
+            } else {
+                Slog.d(TAG, "finish receiver curApp is null? " + r);
+            }
+        }
+
         r.receiver = null;
         r.intent.setComponent(null);
         if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
@@ -452,9 +494,10 @@
             r.resultAbort = false;
         }
 
+        // If we want to wait behind services *AND* we're finishing the head/
+        // active broadcast on its queue
         if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
-                && r.queue.mOrderedBroadcasts.size() > 0
-                && r.queue.mOrderedBroadcasts.get(0) == r) {
+                && r.queue.mDispatcher.getActiveBroadcastLocked() == r) {
             ActivityInfo nextReceiver;
             if (r.nextReceiver < r.receivers.size()) {
                 Object obj = r.receivers.get(r.nextReceiver);
@@ -488,8 +531,8 @@
     }
 
     public void backgroundServicesFinishedLocked(int userId) {
-        if (mOrderedBroadcasts.size() > 0) {
-            BroadcastRecord br = mOrderedBroadcasts.get(0);
+        BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
+        if (br != null) {
             if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
                 Slog.i(TAG, "Resuming delayed broadcast");
                 br.curComponent = null;
@@ -861,7 +904,7 @@
         if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
                 + mQueueName + "]: "
                 + mParallelBroadcasts.size() + " parallel broadcasts, "
-                + mOrderedBroadcasts.size() + " ordered broadcasts");
+                + mDispatcher.totalUndelivered() + " ordered broadcasts");
 
         mService.updateCpuStats();
 
@@ -937,8 +980,12 @@
         boolean looped = false;
 
         do {
-            if (mOrderedBroadcasts.size() == 0) {
-                // No more broadcasts pending, so all done!
+            final long now = SystemClock.uptimeMillis();
+            r = mDispatcher.getNextBroadcastLocked(now);
+
+            if (r == null) {
+                // No more broadcasts are deliverable right now, so all done!
+                mDispatcher.scheduleDeferralCheckLocked(false);
                 mService.scheduleAppGcsLocked();
                 if (looped) {
                     // If we had finished the last ordered broadcast, then
@@ -954,7 +1001,7 @@
 
                 return;
             }
-            r = mOrderedBroadcasts.get(0);
+
             boolean forceReceive = false;
 
             // Ensure that even if something goes awry with the timeout
@@ -967,9 +1014,8 @@
             // significant amounts of time.
             int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
             if (mService.mProcessesReady && r.dispatchTime > 0) {
-                long now = SystemClock.uptimeMillis();
                 if ((numReceivers > 0) &&
-                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+                        (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                     Slog.w(TAG, "Hung broadcast ["
                             + mQueueName + "] discarded after timeout failure:"
                             + " now=" + now
@@ -993,27 +1039,53 @@
                 return;
             }
 
+            // Is the current broadcast is done for any reason?
             if (r.receivers == null || r.nextReceiver >= numReceivers
                     || r.resultAbort || forceReceive) {
-                // No more receivers for this broadcast!  Send the final
-                // result if requested...
+                // Send the final result if requested
                 if (r.resultTo != null) {
-                    try {
-                        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
-                                "Finishing broadcast [" + mQueueName + "] "
-                                + r.intent.getAction() + " app=" + r.callerApp);
-                        performReceiveLocked(r.callerApp, r.resultTo,
-                            new Intent(r.intent), r.resultCode,
-                            r.resultData, r.resultExtras, false, false, r.userId);
-                        // Set this to null so that the reference
-                        // (local and remote) isn't kept in the mBroadcastHistory.
-                        r.resultTo = null;
-                    } catch (RemoteException e) {
-                        r.resultTo = null;
-                        Slog.w(TAG, "Failure ["
-                                + mQueueName + "] sending broadcast result of "
-                                + r.intent, e);
+                    boolean sendResult = true;
 
+                    // if this was part of a split/deferral complex, update the refcount and only
+                    // send the completion when we clear all of them
+                    if (r.splitToken != 0) {
+                        int newCount = mSplitRefcounts.get(r.splitToken) - 1;
+                        if (newCount == 0) {
+                            // done!  clear out this record's bookkeeping and deliver
+                            if (DEBUG_BROADCAST_DEFERRAL) {
+                                Slog.i(TAG, "Sending broadcast completion for split token "
+                                        + r.splitToken);
+                            }
+                            mSplitRefcounts.delete(r.splitToken);
+                        } else {
+                            // still have some split broadcast records in flight; update refcount
+                            // and hold off on the callback
+                            if (DEBUG_BROADCAST_DEFERRAL) {
+                                Slog.i(TAG, "Result refcount " + newCount + " for split token "
+                                        + r.splitToken + " - not sending completion yet");
+                            }
+                            sendResult = false;
+                            mSplitRefcounts.put(r.splitToken, newCount);
+                        }
+                    }
+                    if (sendResult) {
+                        try {
+                            if (DEBUG_BROADCAST) {
+                                Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
+                                        + r.intent.getAction() + " app=" + r.callerApp);
+                            }
+                            performReceiveLocked(r.callerApp, r.resultTo,
+                                    new Intent(r.intent), r.resultCode,
+                                    r.resultData, r.resultExtras, false, false, r.userId);
+                            // Set this to null so that the reference
+                            // (local and remote) isn't kept in the mBroadcastHistory.
+                            r.resultTo = null;
+                        } catch (RemoteException e) {
+                            r.resultTo = null;
+                            Slog.w(TAG, "Failure ["
+                                    + mQueueName + "] sending broadcast result of "
+                                    + r.intent, e);
+                        }
                     }
                 }
 
@@ -1031,11 +1103,76 @@
                     mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                             r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                 }
-                mOrderedBroadcasts.remove(0);
+                mDispatcher.retireBroadcastLocked(r);
                 r = null;
                 looped = true;
                 continue;
             }
+
+            // Check whether the next receiver is under deferral policy, and handle that
+            // accordingly.  If the current broadcast was already part of deferred-delivery
+            // tracking, we know that it must now be deliverable as-is without re-deferral.
+            if (!r.deferred) {
+                final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
+                if (mDispatcher.isDeferringLocked(receiverUid)) {
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
+                                + " at " + r.nextReceiver + " is under deferral");
+                    }
+                    // If this is the only (remaining) receiver in the broadcast, "splitting"
+                    // doesn't make sense -- just defer it as-is and retire it as the
+                    // currently active outgoing broadcast.
+                    BroadcastRecord defer;
+                    if (r.nextReceiver + 1 == numReceivers) {
+                        if (DEBUG_BROADCAST_DEFERRAL) {
+                            Slog.i(TAG, "Sole receiver of " + r
+                                    + " is under deferral; setting aside and proceeding");
+                        }
+                        defer = r;
+                        mDispatcher.retireBroadcastLocked(r);
+                    } else {
+                        // Nontrivial case; split out 'uid's receivers to a new broadcast record
+                        // and defer that, then loop and pick up continuing delivery of the current
+                        // record (now absent those receivers).
+
+                        // The split operation is guaranteed to match at least at 'nextReceiver'
+                        defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
+                        if (DEBUG_BROADCAST_DEFERRAL) {
+                            Slog.i(TAG_BROADCAST, "Post split:");
+                            Slog.i(TAG_BROADCAST, "Original broadcast receivers:");
+                            for (int i = 0; i < r.receivers.size(); i++) {
+                                Slog.i(TAG_BROADCAST, "  " + r.receivers.get(i));
+                            }
+                            Slog.i(TAG_BROADCAST, "Split receivers:");
+                            for (int i = 0; i < defer.receivers.size(); i++) {
+                                Slog.i(TAG_BROADCAST, "  " + defer.receivers.get(i));
+                            }
+                        }
+                        // Track completion refcount as well if relevant
+                        if (r.resultTo != null) {
+                            int token = r.splitToken;
+                            if (token == 0) {
+                                // first split of this record; refcount for 'r' and 'deferred'
+                                r.splitToken = defer.splitToken = nextSplitTokenLocked();
+                                mSplitRefcounts.put(r.splitToken, 2);
+                            } else {
+                                // new split from an already-refcounted situation; increment count
+                                final int curCount = mSplitRefcounts.get(token);
+                                if (DEBUG_BROADCAST_DEFERRAL) {
+                                    if (curCount == 0) {
+                                        Slog.wtf(TAG, "Split refcount is zero with token for " + r);
+                                    }
+                                }
+                                mSplitRefcounts.put(token, curCount + 1);
+                            }
+                        }
+                    }
+                    mDispatcher.addDeferredBroadcast(receiverUid, defer);
+                    r = null;
+                    looped = true;
+                    continue;
+                }
+            }
         } while (r == null);
 
         // Get the next receiver...
@@ -1066,7 +1203,7 @@
                     + mQueueName + "] " + r);
         }
         if (! mPendingBroadcastTimeoutMessage) {
-            long timeoutTime = r.receiverTime + mTimeoutPeriod;
+            long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "Submitting BROADCAST_TIMEOUT_MSG ["
                     + mQueueName + "] for " + r + " at " + timeoutTime);
@@ -1474,12 +1611,12 @@
             mPendingBroadcastTimeoutMessage = false;
         }
 
-        if (mOrderedBroadcasts.size() == 0) {
+        if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {
             return;
         }
 
         long now = SystemClock.uptimeMillis();
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
+        BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
         if (fromMsg) {
             if (!mService.mProcessesReady) {
                 // Only process broadcast timeouts if the system is ready. That way
@@ -1488,7 +1625,7 @@
                 return;
             }
 
-            long timeoutTime = r.receiverTime + mTimeoutPeriod;
+            long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
             if (timeoutTime > now) {
                 // We can observe premature timeouts because we do not cancel and reset the
                 // broadcast timeout message after each receiver finishes.  Instead, we set up
@@ -1503,16 +1640,15 @@
             }
         }
 
-        BroadcastRecord br = mOrderedBroadcasts.get(0);
-        if (br.state == BroadcastRecord.WAITING_SERVICES) {
+        if (r.state == BroadcastRecord.WAITING_SERVICES) {
             // In this case the broadcast had already finished, but we had decided to wait
             // for started services to finish as well before going on.  So if we have actually
             // waited long enough time timeout the broadcast, let's give up on the whole thing
             // and just move on to the next.
-            Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
-                    ? br.curComponent.flattenToShortString() : "(null)"));
-            br.curComponent = null;
-            br.state = BroadcastRecord.IDLE;
+            Slog.i(TAG, "Waited long enough for: " + (r.curComponent != null
+                    ? r.curComponent.flattenToShortString() : "(null)"));
+            r.curComponent = null;
+            r.state = BroadcastRecord.IDLE;
             processNextBroadcast(false);
             return;
         }
@@ -1619,13 +1755,8 @@
             }
         }
 
-        for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
-            didSomething |= mOrderedBroadcasts.get(i).cleanupDisabledPackageReceiversLocked(
-                    packageName, filterByClasses, userId, doit);
-            if (!doit && didSomething) {
-                return true;
-            }
-        }
+        didSomething |= mDispatcher.cleanupDisabledPackageReceiversLocked(packageName,
+                filterByClasses, userId, doit);
 
         return didSomething;
     }
@@ -1665,7 +1796,7 @@
     }
 
     final boolean isIdle() {
-        return mParallelBroadcasts.isEmpty() && mOrderedBroadcasts.isEmpty()
+        return mParallelBroadcasts.isEmpty() && mDispatcher.isEmpty()
                 && (mPendingBroadcast == null);
     }
 
@@ -1677,10 +1808,7 @@
         for (int i = N - 1; i >= 0; i--) {
             mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS);
         }
-        N = mOrderedBroadcasts.size();
-        for (int i = N - 1; i >= 0; i--) {
-            mOrderedBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
-        }
+        mDispatcher.writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
         if (mPendingBroadcast != null) {
             mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST);
         }
@@ -1721,7 +1849,7 @@
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-        if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+        if (!mParallelBroadcasts.isEmpty() || !mDispatcher.isEmpty()
                 || mPendingBroadcast != null) {
             boolean printed = false;
             for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
@@ -1740,29 +1868,12 @@
                 pw.println("  Active Broadcast " + mQueueName + " #" + i + ":");
                 br.dump(pw, "    ", sdf);
             }
-            printed = false;
-            needSep = true;
-            for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
-                BroadcastRecord br = mOrderedBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    printed = true;
-                    pw.println("  Active ordered broadcasts [" + mQueueName + "]:");
-                }
-                pw.println("  Active Ordered Broadcast " + mQueueName + " #" + i + ":");
-                mOrderedBroadcasts.get(i).dump(pw, "    ", sdf);
-            }
+
+            mDispatcher.dumpLocked(pw, dumpPackage, mQueueName, sdf);
+
             if (dumpPackage == null || (mPendingBroadcast != null
                     && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
-                if (needSep) {
-                    pw.println();
-                }
+                pw.println();
                 pw.println("  Pending broadcast [" + mQueueName + "]:");
                 if (mPendingBroadcast != null) {
                     mPendingBroadcast.dump(pw, "    ", sdf);
@@ -1773,6 +1884,8 @@
             }
         }
 
+        mConstants.dump(pw);
+
         int i;
         boolean printed = false;
 
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9e799f6..d9e03f8 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -36,10 +36,12 @@
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * An active intent broadcast.
@@ -64,6 +66,9 @@
     final int[] delivery;   // delivery state of each receiver
     final long[] duration;   // duration a receiver took to process broadcast
     IIntentReceiver resultTo; // who receives final result if non-null
+    boolean deferred;
+    int splitCount;         // refcount for result callback, when split
+    int splitToken;         // identifier for cross-BroadcastRecord refcount
     long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
     long dispatchClockTime; // the clock time the dispatch started
@@ -106,6 +111,9 @@
     ComponentName curComponent; // the receiver class that is currently running.
     ActivityInfo curReceiver;   // info about the receiver that is currently running.
 
+    // Private refcount-management bookkeeping; start > 0
+    static AtomicInteger sNextToken = new AtomicInteger(1);
+
     void dump(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
         final long now = SystemClock.uptimeMillis();
 
@@ -304,6 +312,52 @@
         allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
     }
 
+    /**
+     * Split off a new BroadcastRecord that clones this one, but contains only the
+     * recipient records for the current (just-finished) receiver's app, starting
+     * after the just-finished receiver [i.e. at r.nextReceiver].  Returns null
+     * if there are no matching subsequent receivers in this BroadcastRecord.
+     */
+    BroadcastRecord splitRecipientsLocked(int slowAppUid, int startingAt) {
+        // Do we actually have any matching receivers down the line...?
+        ArrayList splitReceivers = null;
+        for (int i = startingAt; i < receivers.size(); ) {
+            Object o = receivers.get(i);
+            if (getReceiverUid(o) == slowAppUid) {
+                if (splitReceivers == null) {
+                    splitReceivers = new ArrayList<>();
+                }
+                splitReceivers.add(o);
+                receivers.remove(i);
+                break;
+            } else {
+                i++;
+            }
+        }
+
+        // No later receivers in the same app, so we have no more to do
+        if (splitReceivers == null) {
+            return null;
+        }
+
+        // build a new BroadcastRecord around that single-target list
+        BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp,
+                callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+                requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
+                resultData, resultExtras, ordered, sticky, initialSticky, userId,
+                allowBackgroundActivityStarts);
+
+        return split;
+    }
+
+    int getReceiverUid(Object receiver) {
+        if (receiver instanceof BroadcastFilter) {
+            return ((BroadcastFilter) receiver).owningUid;
+        } else /* if (receiver instanceof ResolveInfo) */ {
+            return ((ResolveInfo) receiver).activityInfo.applicationInfo.uid;
+        }
+    }
+
     public BroadcastRecord maybeStripForHistory() {
         if (!intent.canStripForHistory()) {
             return this;
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index b71a751..5b469fe 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -16,6 +16,10 @@
 
 package com.android.server.attention;
 
+import static android.provider.DeviceConfig.AttentionManagerService.NAMESPACE;
+import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_COMPONENT_NAME;
+import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_SERVICE_ENABLED;
+
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -40,6 +44,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.service.attention.AttentionService;
 import android.service.attention.AttentionService.AttentionFailureCodes;
 import android.service.attention.IAttentionCallback;
@@ -66,6 +71,9 @@
 public class AttentionManagerService extends SystemService {
     private static final String LOG_TAG = "AttentionManagerService";
 
+    /** Default value in absence of {@link DeviceConfig} override. */
+    private static final boolean DEFAULT_SERVICE_ENABLED = true;
+
     /** Service will unbind if connection is not used for that amount of time. */
     private static final long CONNECTION_TTL_MILLIS = 60_000;
 
@@ -105,7 +113,7 @@
         super.onBootPhase(phase);
         if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             mComponentName = resolveAttentionService(mContext);
-            if (mComponentName != null) {
+            if (isAttentionServiceSupported()) {
                 // If the service is supported we want to keep receiving the screen off events.
                 mContext.registerReceiver(new ScreenStateReceiver(),
                         new IntentFilter(Intent.ACTION_SCREEN_OFF));
@@ -117,7 +125,12 @@
      * Returns {@code true} if attention service is supported on this device.
      */
     public boolean isAttentionServiceSupported() {
-        return mComponentName != null;
+        return mComponentName != null && isServiceEnabled();
+    }
+
+    private boolean isServiceEnabled() {
+        final String enabled = DeviceConfig.getProperty(NAMESPACE, PROPERTY_SERVICE_ENABLED);
+        return enabled == null ? DEFAULT_SERVICE_ENABLED : "true".equals(enabled);
     }
 
     /**
@@ -266,8 +279,9 @@
      * system.
      */
     private static ComponentName resolveAttentionService(Context context) {
-        // TODO(b/111939367): add a flag to turn on/off.
-        final String componentNameString = context.getString(
+        final String flag = DeviceConfig.getProperty(NAMESPACE, PROPERTY_COMPONENT_NAME);
+
+        final String componentNameString = flag != null ? flag : context.getString(
                 R.string.config_defaultAttentionService);
 
         if (TextUtils.isEmpty(componentNameString)) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 7625aaf..c56db71 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -2040,6 +2040,7 @@
                         if (DEBUG) {
                             Slog.d(TAG, "MSG_CHECK_JOB");
                         }
+                        removeMessages(MSG_CHECK_JOB);
                         if (mReportedActive) {
                             // if jobs are currently being run, queue all ready jobs for execution.
                             queueReadyJobsForExecutionLocked();
@@ -2099,7 +2100,6 @@
                 }
                 maybeRunPendingJobsLocked();
                 // Don't remove JOB_EXPIRED in case one came along while processing the queue.
-                removeMessages(MSG_CHECK_JOB);
             }
         }
     }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 82bfa51..ed1a6d0 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -33,6 +33,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -40,6 +41,7 @@
 import com.android.server.job.GrantedUriPermissions;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobServerProtoEnums;
 import com.android.server.job.JobStatusDumpProto;
 import com.android.server.job.JobStatusShortInfoProto;
 
@@ -80,6 +82,28 @@
     static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
 
+    /**
+     * The constraints that we want to log to statsd.
+     *
+     * Constraints that can be inferred from other atoms have been excluded to avoid logging too
+     * much information and to reduce redundancy:
+     *
+     * * CONSTRAINT_CHARGING can be inferred with PluggedStateChanged (Atom #32)
+     * * CONSTRAINT_BATTERY_NOT_LOW can be inferred with BatteryLevelChanged (Atom #30)
+     * * CONSTRAINT_CONNECTIVITY can be partially inferred with ConnectivityStateChanged
+     * (Atom #98) and BatterySaverModeStateChanged (Atom #20).
+     * * CONSTRAINT_DEVICE_NOT_DOZING can be mostly inferred with DeviceIdleModeStateChanged
+     * (Atom #21)
+     * * CONSTRAINT_BACKGROUND_NOT_RESTRICTED can be inferred with BatterySaverModeStateChanged
+     * (Atom #20)
+     */
+    private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
+            | CONSTRAINT_DEADLINE
+            | CONSTRAINT_IDLE
+            | CONSTRAINT_STORAGE_NOT_LOW
+            | CONSTRAINT_TIMING_DELAY
+            | CONSTRAINT_WITHIN_QUOTA;
+
     // Soft override: ignore constraints like time that don't affect API availability
     public static final int OVERRIDE_SOFT = 1;
     // Full override: ignore all constraints including API-affecting like connectivity
@@ -976,6 +1000,12 @@
         }
         satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
         mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+        if ((STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
+            StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
+                    sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
+                    state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+                            : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+        }
         return true;
     }
 
@@ -1228,37 +1258,70 @@
         }
     }
 
+    /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
+    private int getProtoConstraint(int constraint) {
+        switch (constraint) {
+            case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
+                return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
+            case CONSTRAINT_BATTERY_NOT_LOW:
+                return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW;
+            case CONSTRAINT_CHARGING:
+                return JobServerProtoEnums.CONSTRAINT_CHARGING;
+            case CONSTRAINT_CONNECTIVITY:
+                return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY;
+            case CONSTRAINT_CONTENT_TRIGGER:
+                return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER;
+            case CONSTRAINT_DEADLINE:
+                return JobServerProtoEnums.CONSTRAINT_DEADLINE;
+            case CONSTRAINT_DEVICE_NOT_DOZING:
+                return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
+            case CONSTRAINT_IDLE:
+                return JobServerProtoEnums.CONSTRAINT_IDLE;
+            case CONSTRAINT_STORAGE_NOT_LOW:
+                return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
+            case CONSTRAINT_TIMING_DELAY:
+                return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
+            case CONSTRAINT_WITHIN_QUOTA:
+                return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA;
+            default:
+                return JobServerProtoEnums.CONSTRAINT_UNKNOWN;
+        }
+    }
+
     /** Writes constraints to the given repeating proto field. */
     void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) {
         if ((constraints & CONSTRAINT_CHARGING) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CHARGING);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING);
         }
         if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_BATTERY_NOT_LOW);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW);
         }
         if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_STORAGE_NOT_LOW);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW);
         }
         if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_TIMING_DELAY);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY);
         }
         if ((constraints & CONSTRAINT_DEADLINE) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEADLINE);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE);
         }
         if ((constraints & CONSTRAINT_IDLE) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_IDLE);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE);
         }
         if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY);
         }
         if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER);
         }
         if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEVICE_NOT_DOZING);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING);
         }
         if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_WITHIN_QUOTA);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA);
+        }
+        if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d0ef4f1..d5089cb 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -696,7 +696,7 @@
                 return null;
             }
             return new LauncherApps.AppUsageLimit(
-                    data.isGroupLimit(), data.getTotalUsageLimit(), data.getUsageRemaining());
+                    data.getTotalUsageLimit(), data.getUsageRemaining());
         }
 
         private void ensureShortcutPermission(@NonNull String callingPackage) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 40f10fd..2d89bc7 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -544,6 +544,16 @@
         mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
     }
 
+    private boolean hasVisibleNonFinishingActivity(TaskRecord t) {
+        for (int i = t.mActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = t.mActivities.get(i);
+            if (r.visible && !r.finishing) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void checkVisibility(TaskRecord t, ActivityRecord r) {
         synchronized (mSupervisor.mService.mGlobalLock) {
 
@@ -552,7 +562,7 @@
 
             // If we have an active transition that's waiting on a certain activity that will be
             // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
-            if (info != null && !t.isVisible()) {
+            if (info != null && !hasVisibleNonFinishingActivity(t)) {
                 if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
                         + " activity=" + r);
                 logAppTransitionCancel(info);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b7c35c0..8f39f3d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -161,6 +161,7 @@
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PipModeChangeItem;
 import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.TopResumedActivityChangeItem;
 import android.app.servertransaction.WindowVisibilityItem;
 import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
@@ -692,6 +693,26 @@
         }
     }
 
+    void scheduleTopResumedActivityChanged(boolean onTop) {
+        if (!attachedToProcess()) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.w(TAG, "Can't report activity position update - client not running"
+                                + ", activityRecord=" + this);
+            }
+            return;
+        }
+        try {
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop);
+            }
+
+            mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
+                    TopResumedActivityChangeItem.obtain(onTop));
+        } catch (RemoteException e) {
+            // If process died, whatever.
+        }
+    }
+
     void updateMultiWindowMode() {
         if (task == null || task.getStack() == null || !attachedToProcess()) {
             return;
@@ -3099,6 +3120,7 @@
             transaction.addCallback(callbackItem);
             transaction.setLifecycleStateRequest(lifecycleItem);
             mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+            mRootActivityContainer.updateTopResumedActivityIfNeeded();
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c97e4e8..549567a 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2524,6 +2524,7 @@
             // Protect against recursion.
             mInResumeTopActivity = true;
             result = resumeTopActivityInnerLocked(prev, options);
+            mRootActivityContainer.updateTopResumedActivityIfNeeded();
 
             // When resuming the top activity, it may be necessary to pause the top activity (for
             // example, returning to the lock screen. We suppress the normal pause logic in
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a83ef34..c8a150b 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -840,6 +840,7 @@
 
                 // Schedule transaction.
                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);
+                mRootActivityContainer.updateTopResumedActivityIfNeeded();
 
                 if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mHasHeavyWeightFeature) {
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index e95ac5c..624fdc2 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -175,6 +175,12 @@
     private ActivityDisplay mDefaultDisplay;
     private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
 
+    /**
+     * Cached value of the topmost resumed activity in the system. Updated when new activity is
+     * resumed.
+     */
+    private ActivityRecord mTopResumedActivity;
+
     /** The current user */
     int mCurrentUser;
     /** Stack id of the front stack when user switched, indexed by userId. */
@@ -1145,6 +1151,23 @@
         return result;
     }
 
+    void updateTopResumedActivityIfNeeded() {
+        final ActivityRecord prevTopActivity = mTopResumedActivity;
+        final ActivityStack topStack = getTopDisplayFocusedStack();
+        if (topStack == null || topStack.mResumedActivity == prevTopActivity) {
+            return;
+        }
+        // Clear previous top state
+        if (prevTopActivity != null) {
+            prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */);
+        }
+        // Update the current top activity
+        mTopResumedActivity = topStack.mResumedActivity;
+        if (mTopResumedActivity != null) {
+            mTopResumedActivity.scheduleTopResumedActivityChanged(true /* onTop */);
+        }
+    }
+
     void applySleepTokens(boolean applyToStacks) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             // Set the sleeping state of the display.
@@ -1404,6 +1427,7 @@
             mActivityDisplays.remove(display);
             mActivityDisplays.add(position, display);
         }
+        updateTopResumedActivityIfNeeded();
     }
 
     @VisibleForTesting
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 5d69bbd..4e43d00 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -964,26 +964,6 @@
         assertFalse(hasAppUsageObserver(UID, OBS_ID1));
     }
 
-    /** Verify app usage limit observer added correctly reports it being a group limit */
-    @Test
-    public void testAppUsageLimitObserver_IsGroupLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN);
-        AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
-        assertNotNull("Observer wasn't added", group);
-        assertTrue("Observer didn't correctly report being a group limit",
-                group.isGroupLimit());
-    }
-
-    /** Verify app usage limit observer added correctly reports it being not a group limit */
-    @Test
-    public void testAppUsageLimitObserver_IsNotGroupLimit() {
-        addAppUsageLimitObserver(OBS_ID1, new String[]{PKG_PROD}, TIME_30_MIN);
-        AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
-        assertNotNull("Observer wasn't added", group);
-        assertFalse("Observer didn't correctly report not being a group limit",
-                group.isGroupLimit());
-    }
-
     /** Verify app usage limit observer added correctly reports its total usage limit */
     @Test
     public void testAppUsageLimitObserver_GetTotalUsageLimit() {
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index fa472e2..873ada0 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -510,12 +510,9 @@
     }
 
     class AppUsageLimitGroup extends UsageGroup {
-        private boolean mGroupLimit;
-
         public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId,
                 String[] observed, long timeLimitMs, PendingIntent limitReachedCallback) {
             super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback);
-            mGroupLimit = observed.length > 1;
         }
 
         @Override
@@ -529,11 +526,6 @@
         }
 
         @GuardedBy("mLock")
-        boolean isGroupLimit() {
-            return mGroupLimit;
-        }
-
-        @GuardedBy("mLock")
         long getTotaUsageLimit() {
             return mTimeLimitMs;
         }
@@ -547,14 +539,6 @@
                 return mTimeLimitMs - mUsageTimeMs;
             }
         }
-
-        @Override
-        @GuardedBy("mLock")
-        void dump(PrintWriter pw) {
-            super.dump(pw);
-            pw.print(" groupLimit=");
-            pw.print(mGroupLimit);
-        }
     }
 
 
@@ -692,7 +676,7 @@
                     smallestGroup = otherGroup;
                 }
             }
-            return new UsageStatsManagerInternal.AppUsageLimitData(smallestGroup.isGroupLimit(),
+            return new UsageStatsManagerInternal.AppUsageLimitData(
                     smallestGroup.getTotaUsageLimit(), smallestGroup.getUsageRemaining());
         }
     }
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index b381cbf..0b3bd70 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -79,6 +79,7 @@
             android:singleUser="true" android:exported="true" />
         <receiver android:name="TrackTimeReceiver" />
         <receiver android:name="AlarmSpamReceiver" />
+        <receiver android:name="SlowReceiver" />
         <activity android:name="DisableScreenshotsActivity"
                 android:label="DisableScreenshots"
                 android:theme="@style/DisableScreenshots">
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 0f49608..2581e08 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -16,21 +16,21 @@
 
 package com.google.android.test.activity;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
+import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Bundle;
@@ -42,21 +42,18 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.graphics.Bitmap;
 import android.provider.Settings;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.ScrollView;
-import android.widget.Toast;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.util.Log;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
 
+import java.util.ArrayList;
+import java.util.List;
 
 public class ActivityTestMain extends Activity {
     static final String TAG = "ActivityTest";
@@ -73,8 +70,13 @@
 
     ServiceConnection mIsolatedConnection;
 
+    static final String SLOW_RECEIVER_ACTION = "com.google.android.test.activity.SLOW_ACTION";
+    static final String SLOW_RECEIVER_EXTRA = "slow_ordinal";
+
     static final int MSG_SPAM = 1;
     static final int MSG_SPAM_ALARM = 2;
+    static final int MSG_SLOW_RECEIVER = 3;
+    static final int MSG_SLOW_ALARM_RECEIVER = 4;
 
     final Handler mHandler = new Handler() {
         @Override
@@ -100,11 +102,58 @@
                     mAlarm.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, when+(30*1000), pi);
                     scheduleSpamAlarm(30*1000);
                 } break;
+                case MSG_SLOW_RECEIVER: {
+                    // Several back to back, to illustrate dispatch policy
+                    Intent intent = new Intent(ActivityTestMain.this, SlowReceiver.class);
+                    intent.setAction(SLOW_RECEIVER_ACTION);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 1);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 2);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 3);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                } break;
+                case MSG_SLOW_ALARM_RECEIVER: {
+                    // Several back to back, to illustrate dispatch policy
+                    Intent intent = new Intent(ActivityTestMain.this, SlowReceiver.class);
+                    intent.setAction(SLOW_RECEIVER_ACTION);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 1);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 2);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 3);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+
+                    // Also send a broadcast alarm to evaluate the alarm fast-forward policy
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 4);
+                    PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, 0);
+                    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+                    long now = SystemClock.elapsedRealtime();
+                    Log.i(TAG, "Setting alarm for now + 5 seconds");
+                    am.setExact(AlarmManager.ELAPSED_REALTIME, now + 5_000, pi);
+                } break;
             }
             super.handleMessage(msg);
         }
     };
 
+    final BroadcastReceiver mSlowReceiverCompletion = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int extra = intent.getIntExtra(SLOW_RECEIVER_EXTRA, -1);
+            final String msg = "Slow receiver " + extra + " completed";
+            Toast.makeText(ActivityTestMain.this, msg, Toast.LENGTH_LONG)
+                    .show();
+            Log.i(TAG, msg);
+        }
+    };
+
     class BroadcastResultReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -387,6 +436,18 @@
                 return true;
             }
         });
+        menu.add("Slow receiver").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                scheduleSlowReceiver();
+                return true;
+            }
+        });
+        menu.add("Slow alarm receiver").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                scheduleSlowAlarmReceiver();
+                return true;
+            }
+        });
         menu.add("Spam!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override public boolean onMenuItemClick(MenuItem item) {
                 scheduleSpam(false);
@@ -469,6 +530,7 @@
     protected void onStop() {
         super.onStop();
         mHandler.removeMessages(MSG_SPAM_ALARM);
+        mHandler.removeMessages(MSG_SLOW_RECEIVER);
         for (ServiceConnection conn : mConnections) {
             unbindService(conn);
         }
@@ -544,6 +606,16 @@
         mHandler.sendMessageDelayed(msg, delay);
     }
 
+    void scheduleSlowReceiver() {
+        mHandler.removeMessages(MSG_SLOW_RECEIVER);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SLOW_RECEIVER), 500);
+    }
+
+    void scheduleSlowAlarmReceiver() {
+        mHandler.removeMessages(MSG_SLOW_ALARM_RECEIVER);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SLOW_ALARM_RECEIVER), 500);
+    }
+
     private View scrollWrap(View view) {
         ScrollView scroller = new ScrollView(this);
         scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java
new file mode 100644
index 0000000..0437a28
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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.google.android.test.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class SlowReceiver extends BroadcastReceiver {
+    private static final String TAG = "SlowReceiver";
+    private static final long RECEIVER_DELAY = 6_000;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final int extra = intent.getIntExtra(ActivityTestMain.SLOW_RECEIVER_EXTRA, -1);
+        if (extra == 1) {
+            Log.i(TAG, "Received broadcast 1; delaying return by " + RECEIVER_DELAY + " ms");
+            long now = SystemClock.elapsedRealtime();
+            final long end = now + RECEIVER_DELAY;
+            while (now < end) {
+                try {
+                    Thread.sleep(end - now);
+                } catch (InterruptedException e) { }
+                now = SystemClock.elapsedRealtime();
+            }
+        } else {
+            Log.i(TAG, "Extra parameter not 1, returning immediately");
+        }
+        Log.i(TAG, "Returning from onReceive()");
+    }
+}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index fc4cd01..2690ee8 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -16,8 +16,12 @@
 
 package android.processor.view.inspector;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
@@ -102,6 +106,83 @@
     }
 
     /**
+     * Get a typed list of values for an annotation array property by name.
+     *
+     * The returned list will be empty if the value was left at the default.
+     *
+     * @param propertyName The name of the property to search for
+     * @param valueClass The expected class of the property value
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @param <T> The type of the value
+     * @return A list containing the requested types
+     */
+    <T> List<T> typedArrayValuesByName(
+            String propertyName,
+            Class<T> valueClass,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return untypedArrayValuesByName(propertyName, element, annotationMirror)
+                .stream()
+                .map(annotationValue -> {
+                    final Object value = annotationValue.getValue();
+
+                    if (value == null) {
+                        throw new ProcessingException(
+                                "Unexpected null in array.",
+                                element,
+                                annotationMirror,
+                                annotationValue);
+                    }
+
+                    if (valueClass.isAssignableFrom(value.getClass())) {
+                        return valueClass.cast(value);
+                    } else {
+                        throw new ProcessingException(
+                                String.format(
+                                        "Expected array entry to have type %s, but got %s.",
+                                        valueClass.getCanonicalName(),
+                                        value.getClass().getCanonicalName()),
+                                element,
+                                annotationMirror,
+                                annotationValue);
+                    }
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Get a list of values for an annotation array property by name.
+     *
+     * @param propertyName The name of the property to search for
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @return A list of annotation values, empty list if none found
+     */
+    List<AnnotationValue> untypedArrayValuesByName(
+            String propertyName,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return typedValueByName(propertyName, List.class, element, annotationMirror)
+                .map(untypedValues -> {
+                    List<AnnotationValue> typedValues = new ArrayList<>(untypedValues.size());
+
+                    for (Object untypedValue : untypedValues) {
+                        if (untypedValue instanceof AnnotationValue) {
+                            typedValues.add((AnnotationValue) untypedValue);
+                        } else {
+                            throw new ProcessingException(
+                                    "Unable to convert array entry to AnnotationValue",
+                                    element,
+                                    annotationMirror);
+                        }
+                    }
+
+                    return typedValues;
+                }).orElseGet(Collections::emptyList);
+    }
+
+    /**
      * Get the typed value of an annotation property by name.
      *
      * The returned optional will be empty if the value was left at the default, or if the value
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index f1ebb87..6f58893 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -19,7 +19,9 @@
 import com.squareup.javapoet.ClassName;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -92,6 +94,8 @@
         private final Type mType;
         private boolean mAttributeIdInferrableFromR = true;
         private int mAttributeId = 0;
+        private List<IntEnumEntry> mIntEnumEntries;
+        private List<IntFlagEntry> mIntFlagEntries;
 
         public Property(String name, String getter, Type type) {
             mName = Objects.requireNonNull(name, "Name must not be null");
@@ -133,6 +137,40 @@
             return mType;
         }
 
+        /**
+         * Get the mapping for an {@code int} enumeration, if present.
+         *
+         * @return A list of mapping entries, empty if absent
+         */
+        public List<IntEnumEntry> getIntEnumEntries() {
+            if (mIntEnumEntries != null) {
+                return mIntEnumEntries;
+            } else {
+                return Collections.emptyList();
+            }
+        }
+
+        public void setIntEnumEntries(List<IntEnumEntry> intEnumEntries) {
+            mIntEnumEntries = intEnumEntries;
+        }
+
+        /**
+         * Get the mapping of {@code int} flags, if present.
+         *
+         * @return A list of mapping entries, empty if absent
+         */
+        public List<IntFlagEntry> getIntFlagEntries() {
+            if (mIntFlagEntries != null) {
+                return mIntFlagEntries;
+            } else {
+                return Collections.emptyList();
+            }
+        }
+
+        public void setIntFlagEntries(List<IntFlagEntry> intFlagEntries) {
+            mIntFlagEntries = intFlagEntries;
+        }
+
         public enum Type {
             /** Primitive or boxed {@code boolean} */
             BOOLEAN,
@@ -181,6 +219,7 @@
              * An enumeration packed into an {@code int}.
              *
              * @see android.view.inspector.IntEnumMapping
+             * @see IntEnumEntry
              */
             INT_ENUM,
 
@@ -188,8 +227,74 @@
              * Non-exclusive or partially-exclusive flags packed into an {@code int}.
              *
              * @see android.view.inspector.IntFlagMapping
+             * @see IntFlagEntry
              */
             INT_FLAG
         }
     }
+
+    /**
+     * Model one entry in a int enum mapping.
+     *
+     * @see android.view.inspector.IntEnumMapping
+     */
+    public static final class IntEnumEntry {
+        private final String mName;
+        private final int mValue;
+
+        public IntEnumEntry(String name, int value) {
+            mName = Objects.requireNonNull(name, "Name must not be null");
+            mValue = value;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+    }
+
+    /**
+     * Model one entry in an int flag mapping.
+     *
+     * @see android.view.inspector.IntFlagMapping
+     */
+    public static final class IntFlagEntry {
+        private final String mName;
+        private final int mTarget;
+        private final int mMask;
+
+        public IntFlagEntry(String name, int target, int mask) {
+            mName = Objects.requireNonNull(name, "Name must not be null");
+            mTarget = target;
+            mMask = mask;
+        }
+
+        public IntFlagEntry(String name, int target) {
+            this(name, target, target);
+        }
+
+        /**
+         * Determine if this entry has a bitmask.
+         *
+         * @return True if the bitmask and target are different, false otherwise
+         */
+        public boolean hasMask() {
+            return mTarget != mMask;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public int getTarget() {
+            return mTarget;
+        }
+
+        public int getMask() {
+            return mMask;
+        }
+    }
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index f666be7..42ae890 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -16,13 +16,19 @@
 
 package android.processor.view.inspector;
 
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -63,6 +69,7 @@
 
     /**
      * Set of android and androidx annotation qualified names for colors packed into {@code long}.
+     *
      * @see android.annotation.ColorLong
      */
     private static final String[] COLOR_LONG_ANNOTATION_NAMES = {
@@ -71,7 +78,7 @@
 
     /**
      * @param annotationQualifiedName The qualified name of the annotation to process
-     * @param processingEnv The processing environment from the parent processor
+     * @param processingEnv           The processing environment from the parent processor
      */
     public InspectablePropertyProcessor(
             String annotationQualifiedName,
@@ -109,8 +116,8 @@
      * Check that an element is shaped like a getter.
      *
      * @param element An element that hopefully represents a getter
-     * @throws ProcessingException if the element isn't a getter
      * @return An {@link ExecutableElement} that represents a getter method.
+     * @throws ProcessingException if the element isn't a getter
      */
     private ExecutableElement ensureGetter(Element element) {
         if (element.getKind() != ElementKind.METHOD) {
@@ -144,7 +151,7 @@
             throw new ProcessingException(
                     String.format(
                             "Expected a getter method to take no parameters, "
-                            + "but got %d parameters.",
+                                    + "but got %d parameters.",
                             method.getParameters().size()),
                     element);
         }
@@ -167,10 +174,10 @@
     /**
      * Build a {@link Property} from a getter and an inspectable property annotation.
      *
-     * @param getter An element representing the getter to build from
+     * @param getter     An element representing the getter to build from
      * @param annotation A mirror of an inspectable property-shaped annotation
-     * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
      * @return A property for the getter and annotation
+     * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
      */
     private Property buildProperty(ExecutableElement getter, AnnotationMirror annotation) {
         final String name = mAnnotationUtils
@@ -190,16 +197,25 @@
                 .typedValueByName("attributeId", Integer.class, getter, annotation)
                 .ifPresent(property::setAttributeId);
 
+        switch (property.getType()) {
+            case INT_ENUM:
+                property.setIntEnumEntries(processEnumMapping(getter, annotation));
+                break;
+            case INT_FLAG:
+                property.setIntFlagEntries(processFlagMapping(getter, annotation));
+                break;
+        }
+
         return property;
     }
 
     /**
      * Determine the property type from the annotation, return type, or context clues.
      *
-     * @param getter An element representing the getter to build from
+     * @param getter     An element representing the getter to build from
      * @param annotation A mirror of an inspectable property-shaped annotation
      * @return The resolved property type
-     * @throws ProcessingException If the property type cannot be resolved
+     * @throws ProcessingException If the property type cannot be resolved or is invalid
      * @see android.view.inspector.InspectableProperty#valueType()
      */
     private Property.Type determinePropertyType(
@@ -213,10 +229,62 @@
 
         final Property.Type returnType = convertReturnTypeToPropertyType(getter);
 
+        final boolean hasColor = hasColorAnnotation(getter);
+        final Optional<AnnotationValue> enumMapping =
+                mAnnotationUtils.valueByName("enumMapping", annotation);
+        final Optional<AnnotationValue> flagMapping =
+                mAnnotationUtils.valueByName("flagMapping", annotation);
+
+        if (returnType != Property.Type.INT) {
+            enumMapping.ifPresent(value -> {
+                throw new ProcessingException(
+                        String.format(
+                                "Can only use enumMapping on int types, got %s.",
+                                returnType.toString().toLowerCase()),
+                        getter,
+                        annotation,
+                        value);
+            });
+            flagMapping.ifPresent(value -> {
+                throw new ProcessingException(
+                        String.format(
+                                "Can only use flagMapping on int types, got %s.",
+                                returnType.toString().toLowerCase()),
+                        getter,
+                        annotation,
+                        value);
+            });
+        }
+
         switch (valueType) {
             case "INFERRED":
-                if (hasColorAnnotation(getter)) {
+                if (hasColor) {
+                    enumMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use enumMapping on a color type.",
+                                getter,
+                                annotation,
+                                value);
+                    });
+                    flagMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use flagMapping on a color type.",
+                                getter,
+                                annotation,
+                                value);
+                    });
                     return Property.Type.COLOR;
+                } else if (enumMapping.isPresent()) {
+                    flagMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use flagMapping and enumMapping simultaneously.",
+                                getter,
+                                annotation,
+                                value);
+                    });
+                    return Property.Type.INT_ENUM;
+                } else if (flagMapping.isPresent()) {
+                    return Property.Type.INT_FLAG;
                 } else {
                     return returnType;
                 }
@@ -235,17 +303,14 @@
                                 annotation);
                 }
             case "GRAVITY":
-                if (returnType == Property.Type.INT) {
-                    return Property.Type.GRAVITY;
-                } else {
-                    throw new ProcessingException(
-                            String.format("Gravity must be an integer, got %s", returnType),
-                            getter,
-                            annotation);
-                }
+                requirePackedIntToReturnInt("Gravity", returnType, getter, annotation);
+                return Property.Type.GRAVITY;
             case "INT_ENUM":
+                requirePackedIntToReturnInt("IntEnum", returnType, getter, annotation);
+                return Property.Type.INT_ENUM;
             case "INT_FLAG":
-                throw new ProcessingException("Not implemented", getter, annotation);
+                requirePackedIntToReturnInt("IntFlag", returnType, getter, annotation);
+                return Property.Type.INT_FLAG;
             default:
                 throw new ProcessingException(
                         String.format("Unknown value type enumeration value: %s", valueType),
@@ -258,8 +323,8 @@
      * Get a property type from the return type of a getter.
      *
      * @param getter The getter to extract the return type of
-     * @throws ProcessingException If the return type is not a primitive or an object
      * @return The property type returned by the getter
+     * @throws ProcessingException If the return type is not a primitive or an object
      */
     private Property.Type convertReturnTypeToPropertyType(ExecutableElement getter) {
         final TypeMirror returnType = getter.getReturnType();
@@ -295,6 +360,31 @@
     }
 
     /**
+     * Require that a value type packed into an integer be on a getter that returns an int.
+     *
+     * @param typeName   The name of the type to use in the exception
+     * @param returnType The return type of the getter to check
+     * @param getter     The getter, to use in the exception
+     * @param annotation The annotation, to use in the exception
+     * @throws ProcessingException If the return type is not an int
+     */
+    private static void requirePackedIntToReturnInt(
+            String typeName,
+            Property.Type returnType,
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        if (returnType != Property.Type.INT) {
+            throw new ProcessingException(
+                    String.format(
+                            "%s can only be defined on a method that returns int, got %s.",
+                            typeName,
+                            returnType.toString().toLowerCase()),
+                    getter,
+                    annotation);
+        }
+    }
+
+    /**
      * Determine if a getter is annotated with color annotation matching its return type.
      *
      * Note that an {@code int} return value annotated with {@link android.annotation.ColorLong} is
@@ -303,7 +393,6 @@
      *
      * @param getter The getter to query
      * @return True if the getter has a color annotation, false otherwise
-     *
      */
     private boolean hasColorAnnotation(ExecutableElement getter) {
         switch (unboxType(getter.getReturnType())) {
@@ -353,6 +442,117 @@
     }
 
     /**
+     * Build a model of an {@code int} enumeration mapping from annotation values.
+     *
+     * This method only handles the one-to-one mapping of mirrors of
+     * {@link android.view.inspector.InspectableProperty.EnumMap} annotations into
+     * {@link IntEnumEntry} objects. Further validation should be handled elsewhere
+     *
+     * @see android.view.inspector.IntEnumMapping
+     * @see android.view.inspector.InspectableProperty#enumMapping()
+     * @param getter The getter of the property, used for exceptions
+     * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
+     *                   extract enum mapping values from.
+     * @return A list of int enum entries, in the order specified in source
+     * @throws ProcessingException if mapping doesn't exist or is invalid
+     */
+    private List<IntEnumEntry> processEnumMapping(
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName(
+                "enumMapping", AnnotationMirror.class, getter, annotation);
+        List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size());
+
+        if (enumAnnotations.isEmpty()) {
+            throw new ProcessingException(
+                    "Encountered an empty array for enumMapping", getter, annotation);
+        }
+
+        for (AnnotationMirror enumAnnotation : enumAnnotations) {
+            final String name = mAnnotationUtils.typedValueByName(
+                    "name", String.class, getter, enumAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Name is required for @EnumMap",
+                                getter,
+                                enumAnnotation);
+                    });
+
+            final int value = mAnnotationUtils.typedValueByName(
+                    "value", Integer.class, getter, enumAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Value is required for @EnumMap",
+                                getter,
+                                enumAnnotation);
+                    });
+
+            enumEntries.add(new IntEnumEntry(name, value));
+        }
+
+        return enumEntries;
+    }
+
+    /**
+     * Build a model of an {@code int} flag mapping from annotation values.
+     *
+     * This method only handles the one-to-one mapping of mirrors of
+     * {@link android.view.inspector.InspectableProperty.FlagMap} annotations into
+     * {@link IntFlagEntry} objects. Further validation should be handled elsewhere
+     *
+     * @see android.view.inspector.IntFlagMapping
+     * @see android.view.inspector.InspectableProperty#flagMapping()
+     * @param getter The getter of the property, used for exceptions
+     * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
+     *                   extract flag mapping values from.
+     * @return A list of int flags entries, in the order specified in source
+     * @throws ProcessingException if mapping doesn't exist or is invalid
+     */
+    private List<IntFlagEntry> processFlagMapping(
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName(
+                "flagMapping", AnnotationMirror.class, getter, annotation);
+        List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size());
+
+        if (flagAnnotations.isEmpty()) {
+            throw new ProcessingException(
+                    "Encountered an empty array for flagMapping", getter, annotation);
+        }
+
+        for (AnnotationMirror flagAnnotation : flagAnnotations) {
+            final String name = mAnnotationUtils.typedValueByName(
+                    "name", String.class, getter, flagAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Name is required for @FlagMap",
+                                getter,
+                                flagAnnotation);
+                    });
+
+            final int target = mAnnotationUtils.typedValueByName(
+                    "target", Integer.class, getter, flagAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Target is required for @FlagMap",
+                                getter,
+                                flagAnnotation);
+                    });
+
+            final Optional<Integer> mask = mAnnotationUtils.typedValueByName(
+                    "mask", Integer.class, getter, flagAnnotation);
+
+            if (mask.isPresent()) {
+                flagEntries.add(new IntFlagEntry(name, target, mask.get()));
+            } else {
+                flagEntries.add(new IntFlagEntry(name, target));
+            }
+        }
+
+        return flagEntries;
+    }
+
+    /**
      * Determine if a {@link TypeMirror} is a boxed or unboxed boolean.
      *
      * @param type The type mirror to check
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index dd4d8f5..7b04645 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -16,6 +16,8 @@
 
 package android.processor.view.inspector;
 
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
 import com.squareup.javapoet.ClassName;
@@ -69,6 +71,18 @@
             "android.view.inspector", "PropertyReader");
 
     /**
+     * The class name of {@link android.view.inspector.IntEnumMapping}.
+     */
+    private static final ClassName INT_ENUM_MAPPING = ClassName.get(
+            "android.view.inspector", "IntEnumMapping");
+
+    /**
+     * The class name of {@link android.view.inspector.IntFlagMapping}.
+     */
+    private static final ClassName INT_FLAG_MAPPING = ClassName.get(
+            "android.view.inspector", "IntFlagMapping");
+
+    /**
      * The {@code mPropertiesMapped} field.
      */
     private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec
@@ -248,13 +262,13 @@
         final MethodSpec.Builder builder =  MethodSpec.methodBuilder("readProperties")
                 .addAnnotation(Override.class)
                 .addModifiers(Modifier.PUBLIC)
-                .addParameter(model.getClassName(), "inspectable")
+                .addParameter(model.getClassName(), "node")
                 .addParameter(PROPERTY_READER, "propertyReader")
                 .addCode(generatePropertyMapInitializationCheck());
 
         for (PropertyIdField propertyIdField : propertyIdFields) {
             builder.addStatement(
-                    "propertyReader.read$L($N, inspectable.$L())",
+                    "propertyReader.read$L($N, node.$L())",
                     methodSuffixForPropertyType(propertyIdField.mProperty.getType()),
                     propertyIdField.mFieldSpec,
                     propertyIdField.mProperty.getGetter());
@@ -286,21 +300,22 @@
             if (property.getAttributeId() == ID_NULL) {
                 builder.add("$L", ID_NULL);
             } else {
-                builder.add("$L", String.format("0x%08x", property.getAttributeId()));
+                builder.add("$L", hexLiteral(property.getAttributeId()));
             }
         }
 
         switch (property.getType()) {
             case INT_ENUM:
-                throw new RuntimeException("IntEnumMapping generation not implemented");
+                builder.add(",$W");
+                builder.add(generateIntEnumMappingBuilder(property.getIntEnumEntries()));
+                break;
             case INT_FLAG:
-                throw new RuntimeException("IntFlagMapping generation not implemented");
-            default:
-                builder.add(")");
+                builder.add(",$W");
+                builder.add(generateIntFlagMappingBuilder(property.getIntFlagEntries()));
                 break;
         }
 
-        return builder.build();
+        return builder.add(")").build();
     }
 
     /**
@@ -327,6 +342,56 @@
     }
 
     /**
+     * Generate an invocation of {@link android.view.inspector.IntEnumMapping.Builder}.
+     *
+     * <pre>
+     *      new IntEnumMapping.Builder()
+     *          .addValue("ONE", 1)
+     *          .build()
+     * </pre>
+     *
+     * @return A codeblock containing the an int enum mapping builder
+     */
+    private CodeBlock generateIntEnumMappingBuilder(List<IntEnumEntry> intEnumEntries) {
+        final ArrayList<IntEnumEntry> sortedEntries = new ArrayList<>(intEnumEntries);
+        sortedEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
+
+        final CodeBlock.Builder builder = CodeBlock.builder()
+                .add("new $T()$>", INT_ENUM_MAPPING.nestedClass("Builder"));
+
+        for (IntEnumEntry entry : sortedEntries) {
+            builder.add("\n.addValue($S, $L)", entry.getName(), entry.getValue());
+        }
+
+        return builder.add("\n.build()$<").build();
+    }
+
+    private CodeBlock generateIntFlagMappingBuilder(List<IntFlagEntry> intFlagEntries) {
+        final ArrayList<IntFlagEntry> sortedEntries = new ArrayList<>(intFlagEntries);
+        sortedEntries.sort(Comparator.comparing(IntFlagEntry::getName));
+
+        final CodeBlock.Builder builder = CodeBlock.builder()
+                .add("new $T()$>", INT_FLAG_MAPPING.nestedClass("Builder"));
+
+        for (IntFlagEntry entry : sortedEntries) {
+            if (entry.hasMask()) {
+                builder.add(
+                        "\n.addFlag($S, $L, $L)",
+                        entry.getName(),
+                        hexLiteral(entry.getTarget()),
+                        hexLiteral(entry.getMask()));
+            } else {
+                builder.add(
+                        "\n.addFlag($S, $L)",
+                        entry.getName(),
+                        hexLiteral(entry.getTarget()));
+            }
+        }
+
+        return builder.add("\n.build()$<").build();
+    }
+
+    /**
      * Generate the final class name for the inspection companion from the model's class name.
      *
      * The generated class is added to the same package as the source class. If the class in the
@@ -385,6 +450,10 @@
         }
     }
 
+    private static String hexLiteral(int value) {
+        return String.format("0x%08x", value);
+    }
+
     /**
      * Value class that holds a {@link Property} and a {@link FieldSpec} for that property.
      */
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index 455f5b0..01d9430 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -32,6 +32,7 @@
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 
 
@@ -118,6 +119,12 @@
                 break;
             }
 
+            final Set<Modifier> classModifiers = classElement.get().getModifiers();
+
+            if (classModifiers.contains(Modifier.PRIVATE)) {
+                fail("Enclosing class cannot be private", element);
+            }
+
             final InspectableClassModel model = modelMap.computeIfAbsent(
                     classElement.get().getQualifiedName().toString(),
                     k -> new InspectableClassModel(ClassName.get(classElement.get())));
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index b0775dc..f6d8bb0 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -16,11 +16,13 @@
 
 package android.processor.view.inspector;
 
-import android.processor.view.inspector.InspectableClassModel.Property;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.fail;
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
+import android.processor.view.inspector.InspectableClassModel.Property;
 
 import com.google.common.base.Charsets;
 import com.google.common.io.Resources;
@@ -31,6 +33,7 @@
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.Optional;
 
 /**
@@ -40,7 +43,7 @@
     private static final String RESOURCE_PATH_TEMPLATE =
             "android/processor/view/inspector/InspectionCompanionGeneratorTest/%s.java.txt";
     private static final ClassName TEST_CLASS_NAME =
-            ClassName.get("com.android.inspectable", "TestInspectable");
+            ClassName.get("com.android.node", "TestNode");
     private InspectableClassModel mModel;
     private InspectionCompanionGenerator mGenerator;
 
@@ -59,7 +62,7 @@
     @Test
     public void testNestedClass() {
         mModel = new InspectableClassModel(
-                ClassName.get("com.android.inspectable", "Outer", "Inner"));
+                ClassName.get("com.android.node", "Outer", "Inner"));
         assertGeneratedFileEquals("NestedClass");
     }
 
@@ -105,6 +108,42 @@
         assertGeneratedFileEquals("SuppliedAttributeId");
     }
 
+    @Test
+    public void testIntEnum() {
+        final Property property = new Property(
+                "intEnumProperty",
+                "getIntEnumProperty",
+                Property.Type.INT_ENUM);
+
+        property.setIntEnumEntries(Arrays.asList(
+                new IntEnumEntry("THREE", 3),
+                new IntEnumEntry("TWO", 2),
+                new IntEnumEntry("ONE", 1)));
+
+        mModel.putProperty(property);
+
+        assertGeneratedFileEquals("IntEnum");
+    }
+
+    @Test
+    public void testIntFlag() {
+        final Property property = new Property(
+                "intFlag",
+                "getIntFlag",
+                Property.Type.INT_FLAG);
+
+        property.setAttributeIdInferrableFromR(false);
+        property.setIntFlagEntries(Arrays.asList(
+                new IntFlagEntry("TURBO", 0x1, 0x3),
+                new IntFlagEntry("OVERDRIVE", 0x2, 0x3),
+                new IntFlagEntry("WARP", 0x4)
+        ));
+
+        mModel.putProperty(property);
+
+        assertGeneratedFileEquals("IntFlag");
+    }
+
     private Property addProperty(String name, String getter, Property.Type type) {
         final Property property = new Property(name, getter, type);
         mModel.putProperty(property);
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
new file mode 100644
index 0000000..764aa8b
--- /dev/null
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -0,0 +1,45 @@
+package com.android.node;
+
+import android.R;
+import android.view.inspector.InspectionCompanion;
+import android.view.inspector.IntEnumMapping;
+import android.view.inspector.PropertyMapper;
+import android.view.inspector.PropertyReader;
+import java.lang.Override;
+
+/**
+ * Inspection companion for {@link TestNode}.
+ *
+ * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
+ * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
+ */
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+    /**
+     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     */
+    private boolean mPropertiesMapped = false;
+
+    /**
+     * Property ID of {@code intEnumProperty}.
+     */
+    private int mIntEnumPropertyId;
+
+    @Override
+    public void mapProperties(PropertyMapper propertyMapper) {
+        mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty,
+                new IntEnumMapping.Builder()
+                    .addValue("ONE", 1)
+                    .addValue("TWO", 2)
+                    .addValue("THREE", 3)
+                    .build());
+        mPropertiesMapped = true;
+    }
+
+    @Override
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
+        if (!mPropertiesMapped) {
+            throw new InspectionCompanion.UninitializedPropertyMapException();
+        }
+        propertyReader.readIntEnum(mIntEnumPropertyId, node.getIntEnumProperty());
+    }
+}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
new file mode 100644
index 0000000..75f2813
--- /dev/null
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -0,0 +1,43 @@
+package com.android.node;
+
+import android.view.inspector.InspectionCompanion;
+import android.view.inspector.IntFlagMapping;
+import android.view.inspector.PropertyMapper;
+import android.view.inspector.PropertyReader;
+import java.lang.Override;
+
+/**
+ * Inspection companion for {@link TestNode}.
+ *
+ * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
+ * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
+ */
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+    /**
+     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     */
+    private boolean mPropertiesMapped = false;
+
+    /**
+     * Property ID of {@code intFlag}.
+     */
+    private int mIntFlagId;
+
+    @Override
+    public void mapProperties(PropertyMapper propertyMapper) {
+        mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, new IntFlagMapping.Builder()
+                    .addFlag("OVERDRIVE", 0x00000002, 0x00000003)
+                    .addFlag("TURBO", 0x00000001, 0x00000003)
+                    .addFlag("WARP", 0x00000004)
+                    .build());
+        mPropertiesMapped = true;
+    }
+
+    @Override
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
+        if (!mPropertiesMapped) {
+            throw new InspectionCompanion.UninitializedPropertyMapException();
+        }
+        propertyReader.readIntFlag(mIntFlagId, node.getIntFlag());
+    }
+}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index 2fc242c..0cac462 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -23,7 +23,7 @@
     }
 
     @Override
-    public void readProperties(Outer.Inner inspectable, PropertyReader propertyReader) {
+    public void readProperties(Outer.Inner node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 23d0f78..ce0f867 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -6,12 +6,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * Inspection companion for {@link TestNode}.
  *
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -29,10 +29,10 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readInt(mNoAttributePropertyId, inspectable.getNoAttributeProperty());
+        propertyReader.readInt(mNoAttributePropertyId, node.getNoAttributeProperty());
     }
 }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
index 1142548..f7357fe 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -7,12 +7,12 @@
 import java.lang.String;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * Inspection companion for {@link TestNode}.
  *
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -24,7 +24,7 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 57eb080..dfc1bce 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.R;
 import android.view.inspector.InspectionCompanion;
@@ -7,12 +7,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * Inspection companion for {@link TestNode}.
  *
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -90,20 +90,20 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readBoolean(mBooleanId, inspectable.getBoolean());
-        propertyReader.readByte(mByteId, inspectable.getByte());
-        propertyReader.readChar(mCharId, inspectable.getChar());
-        propertyReader.readColor(mColorId, inspectable.getColor());
-        propertyReader.readDouble(mDoubleId, inspectable.getDouble());
-        propertyReader.readFloat(mFloatId, inspectable.getFloat());
-        propertyReader.readGravity(mGravityId, inspectable.getGravity());
-        propertyReader.readInt(mIntId, inspectable.getInt());
-        propertyReader.readLong(mLongId, inspectable.getLong());
-        propertyReader.readObject(mObjectId, inspectable.getObject());
-        propertyReader.readShort(mShortId, inspectable.getShort());
+        propertyReader.readBoolean(mBooleanId, node.getBoolean());
+        propertyReader.readByte(mByteId, node.getByte());
+        propertyReader.readChar(mCharId, node.getChar());
+        propertyReader.readColor(mColorId, node.getColor());
+        propertyReader.readDouble(mDoubleId, node.getDouble());
+        propertyReader.readFloat(mFloatId, node.getFloat());
+        propertyReader.readGravity(mGravityId, node.getGravity());
+        propertyReader.readInt(mIntId, node.getInt());
+        propertyReader.readLong(mLongId, node.getLong());
+        propertyReader.readObject(mObjectId, node.getObject());
+        propertyReader.readShort(mShortId, node.getShort());
     }
 }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index 6b6ce21..d72cdd5 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -6,12 +6,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * Inspection companion for {@link TestNode}.
  *
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -30,10 +30,10 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readInt(mSuppliedAttributePropertyId, inspectable.getSuppliedAttributeProperty());
+        propertyReader.readInt(mSuppliedAttributePropertyId, node.getSuppliedAttributeProperty());
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0668239..e5733ed 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1221,7 +1221,6 @@
      * @param scanResults a list of scanResult that represents the BSSID
      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1264,7 +1263,6 @@
      *
      * @param scanResults a list of ScanResult
      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1291,7 +1289,6 @@
      *
      * @param osuProviders a set of {@link OsuProvider}
      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1720,8 +1717,8 @@
      * FQDN, the new configuration will replace the existing configuration.
      *
      * @param config The Passpoint configuration to be added
-     * @throws IllegalArgumentException if configuration is invalid
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
+     *                                  the device.
      */
     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
@@ -1737,8 +1734,8 @@
      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
      *
      * @param fqdn The FQDN of the Passpoint configuration to be removed
-     * @throws IllegalArgumentException if no configuration is associated with the given FQDN.
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
+     *                                  Passpoint is not enabled on the device.
      * @deprecated This is no longer supported.
      */
     @Deprecated
@@ -1762,7 +1759,6 @@
      * An empty list will be returned when no configurations are installed.
      *
      * @return A list of {@link PasspointConfiguration}
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @deprecated This is no longer supported.
      */
     @Deprecated