Merge "Create new windows on *other* side in multi-window mode."
diff --git a/Android.mk b/Android.mk
index 5983b30..52ed634 100644
--- a/Android.mk
+++ b/Android.mk
@@ -187,6 +187,8 @@
 	core/java/android/hardware/location/IGeofenceHardware.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
+	core/java/android/hardware/location/IContextHubCallback.aidl \
+	core/java/android/hardware/location/IContextHubService.aidl \
 	core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/ICaptivePortal.aidl \
diff --git a/api/current.txt b/api/current.txt
index aa503af1..f13601e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29592,6 +29592,8 @@
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
+    method public void setStorageDefault();
+    method public void setStorageDeviceEncrypted();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -32042,6 +32044,7 @@
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/api/system-current.txt b/api/system-current.txt
index 95c19d7..0d33503 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9956,6 +9956,7 @@
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+    method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
     method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
     method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
@@ -15123,6 +15124,66 @@
 
 package android.hardware.location {
 
+  public class ContextHubInfo {
+    ctor public ContextHubInfo();
+    method public int describeContents();
+    method public int getId();
+    method public android.hardware.location.MemoryRegion[] getMemoryRegions();
+    method public java.lang.String getName();
+    method public float getPeakMips();
+    method public float getPeakPowerDrawMw();
+    method public int getPlatformVersion();
+    method public float getSleepPowerDrawMw();
+    method public int getStaticSwVersion();
+    method public float getStoppedPowerDrawMw();
+    method public int[] getSupportedSensors();
+    method public java.lang.String getToolchain();
+    method public int getToolchainVersion();
+    method public java.lang.String getVendor();
+    method public void setId(int);
+    method public void setMemoryRegions(android.hardware.location.MemoryRegion[]);
+    method public void setName(java.lang.String);
+    method public void setPeakMips(float);
+    method public void setPeakPowerDrawMw(float);
+    method public void setPlatformVersion(int);
+    method public void setSleepPowerDrawMw(float);
+    method public void setStaticSwVersion(int);
+    method public void setStoppedPowerDrawMw(float);
+    method public void setSupportedSensors(int[]);
+    method public void setToolchain(java.lang.String);
+    method public void setToolchainVersion(int);
+    method public void setVendor(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
+  }
+
+  public final class ContextHubManager {
+    method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+    method public int[] getContexthubHandles();
+    method public android.hardware.location.ContextHubInfo getContexthubInfo(int);
+    method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+    method public int loadNanoApp(int, android.hardware.location.NanoApp);
+    method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
+    method public int unloadNanoApp(int);
+    field public static final int ANY_HUB = -1; // 0xffffffff
+    field public static final int MSG_DATA_SEND = 3; // 0x3
+    field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
+    field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
+  }
+
+  public class ContextHubMessage {
+    ctor public ContextHubMessage(int, int, byte[]);
+    method public int describeContents();
+    method public byte[] getData();
+    method public int getMsgType();
+    method public int getVersion();
+    method public void setMsgData(byte[]);
+    method public void setMsgType(int);
+    method public void setVersion(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+  }
+
   public final class GeofenceHardware {
     ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
     method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
@@ -15239,6 +15300,89 @@
     method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
   }
 
+  public class MemoryRegion implements android.os.Parcelable {
+    ctor public MemoryRegion(android.os.Parcel);
+    method public int describeContents();
+    method public int getCapacityBytes();
+    method public int getFreeCapacityBytes();
+    method public boolean isExecutable();
+    method public boolean isReadable();
+    method public boolean isWritable();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
+  }
+
+  public class NanoApp {
+    ctor public NanoApp();
+    method public int describeContents();
+    method public byte[] getAppBinary();
+    method public int getAppId();
+    method public int getAppVersion();
+    method public java.lang.String getName();
+    method public int getNeededExecMemBytes();
+    method public int getNeededReadMemBytes();
+    method public int[] getNeededSensors();
+    method public int getNeededWriteMemBytes();
+    method public int[] getOutputEvents();
+    method public java.lang.String getPublisher();
+    method public void setAppBinary(byte[]);
+    method public void setAppId(int);
+    method public void setAppVersion(int);
+    method public void setName(java.lang.String);
+    method public void setNeededExecMemBytes(int);
+    method public void setNeededReadMemBytes(int);
+    method public void setNeededSensors(int[]);
+    method public void setNeededWriteMemBytes(int);
+    method public void setOutputEvents(int[]);
+    method public void setPublisher(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
+  }
+
+  public class NanoAppFilter {
+    ctor public NanoAppFilter(long, int, int, long);
+    method public int describeContents();
+    method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int APP_ANY = -1; // 0xffffffff
+    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+    field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+    field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+    field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+    field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+    field public static final int HUB_ANY = -1; // 0xffffffff
+    field public static final int VENDOR_ANY = -1; // 0xffffffff
+  }
+
+  public class NanoAppInstanceInfo {
+    ctor public NanoAppInstanceInfo();
+    method public int describeContents();
+    method public int getAppId();
+    method public int getAppVersion();
+    method public int getContexthubId();
+    method public int getHandle();
+    method public java.lang.String getName();
+    method public int getNeededExecMemBytes();
+    method public int getNeededReadMemBytes();
+    method public int[] getNeededSensors();
+    method public int getNeededWriteMemBytes();
+    method public int[] getOutputEvents();
+    method public java.lang.String getPublisher();
+    method public void setAppId(int);
+    method public void setAppVersion(int);
+    method public void setContexthubId(int);
+    method public void setHandle(int);
+    method public void setName(java.lang.String);
+    method public void setNeededExecMemBytes(int);
+    method public void setNeededReadMemBytes(int);
+    method public void setNeededSensors(int[]);
+    method public void setNeededWriteMemBytes(int);
+    method public void setOutputEvents(int[]);
+    method public void setPublisher(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
+  }
+
 }
 
 package android.hardware.radio {
@@ -31062,6 +31206,7 @@
     method public deprecated boolean isOwner();
     method public boolean isSystem();
     method public static int myUserId();
+    method public static android.os.UserHandle of(int);
     method public static android.os.UserHandle readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -31076,6 +31221,7 @@
     method public android.os.PersistableBundle getSeedAccountOptions();
     method public java.lang.String getSeedAccountType();
     method public long getSerialNumberForUser(android.os.UserHandle);
+    method public long[] getSerialNumbersOfUsers(boolean);
     method public int getUserCount();
     method public long getUserCreationTime(android.os.UserHandle);
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -31493,6 +31639,9 @@
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
+    method public void setStorageCredentialEncrypted();
+    method public void setStorageDefault();
+    method public void setStorageDeviceEncrypted();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -34075,6 +34224,7 @@
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/api/test-current.txt b/api/test-current.txt
index 081c471..48fd6f0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29602,6 +29602,8 @@
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
+    method public void setStorageDefault();
+    method public void setStorageDeviceEncrypted();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -32055,6 +32057,7 @@
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bc17f8..be93926 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -49,7 +49,8 @@
 import java.util.List;
 
 /**
- * An accessibility service runs in the background and receives callbacks by the system
+ * Accessibility services are intended to assist users with disabilities in using
+ * Android devices and apps. They run in the background and receive callbacks by the system
  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
  * in the user interface, for example, the focus has changed, a button has been clicked,
  * etc. Such a service can optionally request the capability for querying the content
@@ -66,22 +67,31 @@
  * <h3>Lifecycle</h3>
  * <p>
  * The lifecycle of an accessibility service is managed exclusively by the system and
- * follows the established service life cycle. Additionally, starting or stopping an
- * accessibility service is triggered exclusively by an explicit user action through
- * enabling or disabling it in the device settings. After the system binds to a service it
- * calls {@link AccessibilityService#onServiceConnected()}. This method can be
- * overriden by clients that want to perform post binding setup.
+ * follows the established service life cycle. Starting an accessibility service is triggered
+ * exclusively by the user explicitly turning the service on in device settings. After the system
+ * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
+ * be overriden by clients that want to perform post binding setup.
+ * </p>
+ * <p>
+ * An accessibility service stops either when the user turns it off in device settings or when
+ * it calls {@link AccessibilityService#disableSelf()}.
  * </p>
  * <h3>Declaration</h3>
  * <p>
- * An accessibility is declared as any other service in an AndroidManifest.xml but it
- * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Additionally an accessibility service must request the
- * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
- * that only the system
- * can bind to it. Failure to declare this intent will cause the system to ignore the
- * accessibility service. Following is an example declaration:
+ * An accessibility is declared as any other service in an AndroidManifest.xml, but it
+ * must do two things:
+ * <ul>
+ *     <ol>
+ *         Specify that it handles the "android.accessibilityservice.AccessibilityService"
+ *         {@link android.content.Intent}.
+ *     </ol>
+ *     <ol>
+ *         Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
+ *         ensure that only the system can bind to it.
+ *     </ol>
+ * </ul>
+ * If either of these items is missing, the system will ignore the accessibility service.
+ * Following is an example declaration:
  * </p>
  * <pre> &lt;service android:name=".MyAccessibilityService"
  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
@@ -135,48 +145,24 @@
  * </ul>
  * <h3>Retrieving window content</h3>
  * <p>
- * A service can specify in its declaration that it can retrieve the active window
- * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * A service can specify in its declaration that it can retrieve window
+ * content which is represented as a tree of {@link AccessibilityWindowInfo} and
+ * {@link AccessibilityNodeInfo} objects. Note that
  * declaring this capability requires that the service declares its configuration via
  * an XML resource referenced by {@link #SERVICE_META_DATA}.
  * </p>
  * <p>
- * For security purposes an accessibility service can retrieve only the content of the
- * currently active window. The currently active window is defined as the window from
- * which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * In other words, the last window that was shown or the last window that the user has touched
- * during touch exploration.
- * </p>
- * <p>
- * The entry point for retrieving window content is through calling
- * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
- * event of the above types or a previous event from the same window
- * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
- * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
- * window content which represented as a tree of such objects.
+ * Window content may be retrieved with
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
+ * {@link AccessibilityService#findFocus(int)},
+ * {@link AccessibilityService#getWindows()}, or
+ * {@link AccessibilityService#getRootInActiveWindow()}.
  * </p>
  * <p class="note">
  * <strong>Note</strong> An accessibility service may have requested to be notified for
- * a subset of the event types, thus be unaware that the active window has changed. Therefore
- * accessibility service that would like to retrieve window content should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track for the active
- * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
- * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
- * methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
- * active window has changed and the service did not get the accessibility event yet. Note
- * that it is possible to have a retrieval method failing even adopting the strategy
- * specified in the previous bullet because the accessibility event dispatch is asynchronous
- * and crosses process boundaries.
- * </li>
- * </ul>
+ * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
+ * possible for a node to contain outdated information because the window content may change at any
+ * time.
  * </p>
  * <h3>Notification strategy</h3>
  * <p>
@@ -328,7 +314,6 @@
      *     android:settingsActivity="foo.bar.TestBackActivity"
      *     android:canRetrieveWindowContent="true"
      *     android:canRequestTouchExplorationMode="true"
-     *     android:canRequestEnhancedWebAccessibility="true"
      *     . . .
      * /&gt;</pre>
      */
@@ -528,6 +513,14 @@
      * is currently touching or the window with input focus, if the user is not
      * touching any window.
      * <p>
+     * The currently active window is defined as the window that most recently fired one
+     * of the following events:
+     * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+     * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+     * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+     * In other words, the last window shown that also has input focus.
+     * </p>
+     * <p>
      * <strong>Note:</strong> In order to access the root node your service has
      * to declare the capability to retrieve window content by setting the
      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -541,8 +534,8 @@
     }
 
     /**
-     * This method allows accessibility service turn itself off
-     * and the service will become disabled from the Settings.
+     * Disables the service. After calling this method, the service will be disabled and settings
+     * will show that it is turned off.
      */
     public final void disableSelf() {
         final IAccessibilityServiceConnection connection =
@@ -1054,7 +1047,7 @@
      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
      * Also the service has to opt-in to retrieve the interactive windows by
      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
-     * flag.Otherwise, the search will be performed only in the active window.
+     * flag. Otherwise, the search will be performed only in the active window.
      * </p>
      *
      * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0fce4e2..a88aa3125 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -165,14 +165,18 @@
                     mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
         }
 
-        if (right.mEndTimeStamp > mEndTimeStamp) {
+        if (right.mBeginTimeStamp > mBeginTimeStamp) {
+            // The incoming UsageStat begins after this one, so use its last time used fields
+            // as the source of truth.
+            // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+            // regards to their mEndTimeStamp.
             mLastEvent = right.mLastEvent;
-            mEndTimeStamp = right.mEndTimeStamp;
             mLastTimeUsed = right.mLastTimeUsed;
             mBeginIdleTime = right.mBeginIdleTime;
             mLastTimeSystemUsed = right.mLastTimeSystemUsed;
         }
         mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+        mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
         mTotalTimeInForeground += right.mTotalTimeInForeground;
         mLaunchCount += right.mLaunchCount;
     }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aaa02bd..3a94bf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3632,7 +3632,7 @@
      *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
      *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
      *         to modify the data returned.
-     * @param userId The userId of the user being queried.
+     * @param userHandle UserHandle of the user being queried.
      *
      * @return Returns a List of ResolveInfo objects containing one entry for each
      *         matching receiver, ordered from best to worst. If there are no matching
@@ -3653,9 +3653,19 @@
      *
      * @hide
      */
+    @SystemApi
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+            @ResolveInfoFlags int flags, UserHandle userHandle) {
+        return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
+    }
+
+    /**
+     * @hide
+     */
     public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId);
 
+
     /** {@hide} */
     @Deprecated
     public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9319c2e..44cd003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3491,6 +3491,7 @@
         info.maxRecents = target.info.maxRecents;
         info.layout = target.info.layout;
         info.resizeMode = target.info.resizeMode;
+        info.encryptionAware = target.info.encryptionAware;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
diff --git a/core/java/android/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
new file mode 100644
index 0000000..1a9221a
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
new file mode 100644
index 0000000..e47c541
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+  */
+@SystemApi
+public class ContextHubInfo {
+    private int mId;
+    private String mName;
+    private String mVendor;
+    private String mToolchain;
+    private int mPlatformVersion;
+    private int mStaticSwVersion;
+    private int mToolchainVersion;
+    private float mPeakMips;
+    private float mStoppedPowerDrawMw;
+    private float mSleepPowerDrawMw;
+    private float mPeakPowerDrawMw;
+
+    private int[] mSupportedSensors;
+
+    private MemoryRegion[] mMemoryRegions;
+
+    public ContextHubInfo() {
+    }
+
+    /**
+     * get the context hub unique identifer
+     *
+     * @return int - unique system wide identifier
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * set the context hub unique identifer
+     *
+     * @param id - unique system wide identifier for the hub
+     */
+    public void setId(int id) {
+        mId = id;
+    }
+
+    /**
+     * get a string as a hub name
+     *
+     * @return String - a name for the hub
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * set a string as the hub name
+     *
+     * @param String - the name for the hub
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * get a string as the vendor name
+     *
+     * @return String - a name for the vendor
+     */
+    public String getVendor() {
+        return mVendor;
+    }
+
+    /**
+     * set a string as the vendor name
+     *
+     * @param String - a name for the vendor
+     */
+    public void setVendor(String vendor) {
+        mVendor = vendor;
+    }
+
+    /**
+     * get tool chain string
+     *
+     * @return String - description of the tool chain
+     */
+    public String getToolchain() {
+        return mToolchain;
+    }
+
+    /**
+     * set tool chain string
+     *
+     * @param String - description of the tool chain
+     */
+    public void setToolchain(String toolchain) {
+        mToolchain = toolchain;
+    }
+
+    /**
+     * get platform version
+     *
+     * @return int - platform version number
+     */
+    public int getPlatformVersion() {
+        return mPlatformVersion;
+    }
+
+    /**
+     * set platform version
+     *
+     * @param platformVersion - platform version number
+     */
+    public void setPlatformVersion(int platformVersion) {
+        mPlatformVersion = platformVersion;
+    }
+
+    /**
+     * get static platform version number
+     *
+     * @return int - platform version number
+     */
+    public int getStaticSwVersion() {
+        return mStaticSwVersion;
+    }
+
+    /**
+     * set platform software version
+     *
+     * @param staticSwVersion - platform static s/w version number
+     */
+    public void setStaticSwVersion(int staticSwVersion) {
+        mStaticSwVersion = staticSwVersion;
+    }
+
+    /**
+     * get the tool chain version
+     *
+     * @return int - the tool chain version
+     */
+    public int getToolchainVersion() {
+        return mToolchainVersion;
+    }
+
+    /**
+     * set the tool chain version number
+     *
+     * @param toolchainVersion - tool chain version number
+     */
+    public void setToolchainVersion(int toolchainVersion) {
+        mToolchainVersion = toolchainVersion;
+    }
+
+    /**
+     * get the peak processing mips the hub can support
+     *
+     * @return float - peak MIPS that this hub can deliver
+     */
+    public float getPeakMips() {
+        return mPeakMips;
+    }
+
+    /**
+     * set the peak mips that this hub can support
+     *
+     * @param peakMips - peak mips this hub can deliver
+     */
+    public void setPeakMips(float peakMips) {
+        mPeakMips = peakMips;
+    }
+
+    /**
+     * get the stopped power draw in milliwatts
+     * This assumes that the hub enter a stopped state - which is
+     * different from the sleep state. Latencies on exiting the
+     * sleep state are typically higher and expect to be in multiple
+     * milliseconds.
+     *
+     * @return float - power draw by the hub in stopped state
+     */
+    public float getStoppedPowerDrawMw() {
+        return mStoppedPowerDrawMw;
+    }
+
+    /**
+     * Set the power consumed by the hub in stopped state
+     *
+     * @param stoppedPowerDrawMw - stopped power in milli watts
+     */
+    public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
+        mStoppedPowerDrawMw = stoppedPowerDrawMw;
+    }
+
+    /**
+     * get the power draw of the hub in sleep mode. This assumes
+     * that the hub supports a sleep mode in which the power draw is
+     * lower than the power consumed when the hub is actively
+     * processing. As a guideline, assume that the hub should be
+     * able to enter sleep mode if it knows reliably on completion
+     * of some task that the next interrupt/scheduled work item is
+     * at least 250 milliseconds later.
+     *
+     * @return float - sleep power draw in milli watts
+     */
+    public float getSleepPowerDrawMw() {
+        return mSleepPowerDrawMw;
+    }
+
+    /**
+     * Set the sleep power draw in milliwatts
+     *
+     * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+     */
+    public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
+        mSleepPowerDrawMw = sleepPowerDrawMw;
+    }
+
+    /**
+     * get the peak powe draw of the hub. This is the power consumed
+     * by the hub at maximum load.
+     *
+     * @return float - peak power draw
+     */
+    public float getPeakPowerDrawMw() {
+        return mPeakPowerDrawMw;
+    }
+
+    /**
+     * set the peak power draw of the hub
+     *
+     * @param peakPowerDrawMw - peak power draw of the hub in
+     *                        milliwatts.
+     */
+    public void setPeakPowerDrawMw(float peakPowerDrawMw) {
+        mPeakPowerDrawMw = peakPowerDrawMw;
+    }
+
+    /**
+     * get the sensors supported by this hub
+     *
+     * @return int[] - all the supported sensors on this hub
+     *
+     * @see ContextHubManager
+     */
+    public int[] getSupportedSensors() {
+        return Arrays.copyOf(mSupportedSensors, mSupportedSensors.length);
+    }
+
+    /**
+     * get the various memory regions on this hub
+     *
+     * @return MemoryRegion[] - all the memory regions on this hub
+     *
+     * @see MemoryRegion
+     */
+    public MemoryRegion[] getMemoryRegions() {
+        return Arrays.copyOf(mMemoryRegions, mMemoryRegions.length);
+    }
+
+    /**
+     * set the supported sensors on this hub
+     *
+     * @param supportedSensors - supported sensors on this hub
+     */
+    public void setSupportedSensors(int[] supportedSensors) {
+        mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
+    }
+
+    /**
+     * set memory regions for this hub
+     *
+     * @param memoryRegions - memory regions information
+     *
+     * @see MemoryRegion
+     */
+    public void setMemoryRegions(MemoryRegion[] memoryRegions) {
+        mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
+    }
+
+    private ContextHubInfo(Parcel in) {
+        mId = in.readInt();
+        mName = in.readString();
+        mVendor = in.readString();
+        mToolchain = in.readString();
+        mPlatformVersion = in.readInt();
+        mToolchainVersion = in.readInt();
+        mStaticSwVersion = in.readInt();
+        mPeakMips = in.readFloat();
+        mStoppedPowerDrawMw = in.readFloat();
+        mSleepPowerDrawMw = in.readFloat();
+        mPeakPowerDrawMw = in.readFloat();
+
+        int numSupportedSensors = in.readInt();
+        mSupportedSensors = new int[numSupportedSensors];
+        in.readIntArray(mSupportedSensors);
+        mMemoryRegions = in.createTypedArray(MemoryRegion.CREATOR);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mId);
+        out.writeString(mName);
+        out.writeString(mVendor);
+        out.writeString(mToolchain);
+        out.writeInt(mPlatformVersion);
+        out.writeInt(mToolchainVersion);
+        out.writeInt(mStaticSwVersion);
+        out.writeFloat(mPeakMips);
+        out.writeFloat(mStoppedPowerDrawMw);
+        out.writeFloat(mSleepPowerDrawMw);
+        out.writeFloat(mPeakPowerDrawMw);
+
+        out.writeInt(mSupportedSensors.length);
+        out.writeIntArray(mSupportedSensors);
+        out.writeTypedArray(mMemoryRegions, flags);
+    }
+
+    public static final Parcelable.Creator<ContextHubInfo> CREATOR
+            = new Parcelable.Creator<ContextHubInfo>() {
+        public ContextHubInfo createFromParcel(Parcel in) {
+            return new ContextHubInfo(in);
+        }
+
+        public ContextHubInfo[] newArray(int size) {
+            return new ContextHubInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
new file mode 100644
index 0000000..301b2e4
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.Manifest;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A class that exposes the Context hubs on a device to
+ * applicaions.
+ *
+ * Please not that this class is not expected to be used by
+ * unbundled applications. Also, calling applications are
+ * expected to have LOCTION_HARDWARE premissions to use this
+ * class.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContextHubManager {
+
+    private static final String TAG = "ContextHubManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+    private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+            + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+
+    private Context mContext;
+    private IContextHubService mContextHubService;
+    private boolean mContextHubConnected;
+
+    /**
+     * A special context hub identifer meaning any possible hub on
+     * the system.
+     */
+    public static final int ANY_HUB       = -1;
+    /**
+     * A constant denoting a message to load a a Nano App
+     */
+    public static final int MSG_LOAD_NANO_APP   = 1;
+    /**
+     * A constant denoting a message to unload a a Nano App
+     */
+    public static final int MSG_UNLOAD_NANO_APP = 2;
+    /**
+     * A constant denoting a message to send a message
+     */
+    public static final int MSG_DATA_SEND       = 3;
+
+
+    /**
+     * Get a handle to all the context hubs in the system
+     * @return array of context hub handles
+     */
+    public int[] getContexthubHandles() {
+        int[] retVal = null;
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.getContextHubHandles();
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch context hub handles :" + e.toString());
+            }
+        }
+        return retVal;
+    }
+
+    /**
+     * Get more information about a specific hub.
+     *
+     * @param contexthubHandle Handle of context hub
+     *
+     * @return ContextHubInfo  returned information about the hub
+     *
+     * @see ContextHubInfo
+     */
+    public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+        ContextHubInfo retVal = null;
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.getContextHubInfo(contexthubHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch context hub info :" + e.toString());
+            }
+        }
+
+        return(retVal);
+    }
+
+    /**
+     * Load a nanoapp on a specified context hub
+     *
+     * @param hubHandle handle of context hub to load the app on.
+     * @param app the nanoApp to load on the hub
+     *
+     * @return int nanoAppInstance of the loaded nanoApp on success,
+     *         -1 otherwise
+     *
+     * @see NanoApp
+     */
+    public int loadNanoApp(int hubHandle, NanoApp app) {
+        int retVal = -1;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.loadNanoApp(hubHandle, app);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch load nanoApp :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Unload a specified nanoApp
+     *
+     * @param nanoAppInstanceHandle handle of the nanoApp to load
+     *
+     * @return int  0 on success, -1 otherewise
+     */
+    public int unloadNanoApp(int nanoAppInstanceHandle) {
+        int retVal = -1;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * get information about the nano app instance
+     *
+     * @param nanoAppInstanceHandle handle of the nanoAppInstance
+     *
+     * @return NanoAppInstanceInfo Inforamtion about the nano app
+     *         instance.
+     *
+     * @see NanoAppInstanceInfo
+     */
+    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+        NanoAppInstanceInfo retVal = null;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Find a specified nano app on the system
+     *
+     * @param hubHandle handle of hub to search for nano app
+     * @param filter filter specifying the search criteria for app
+     *
+     * @see NanoAppFilter
+     *
+     * @return Integer[] Array of handles to any found nano apps
+     */
+    public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+        int[] temp;
+        Integer[] retVal = null;
+
+        if(mContextHubConnected) {
+            try {
+                temp = mContextHubService.findNanoAppOnHub(hubHandle, filter);
+                retVal = new Integer[temp.length];
+                for (int i = 0; i < temp.length; i++) {
+                    retVal[i] = temp[i];
+                }
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not query nanoApp instance :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Send a message to a spcific nano app instance on a context
+     * hub
+     *
+     *
+     * @param hubHandle handle of the hub to send the message to
+     * @param nanoAppHandle  handle of the nano app to send to
+     * @param msg Message to be sent
+     *
+     * @see ContextHubMessage
+     *
+     * @return int 0 on success, -1 otherwise
+     */
+    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) {
+        int retVal = -1;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.sendMessage(hubHandle, nanoAppHandle, msg);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch send message :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    private void checkPermissions() {
+        mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+    }
+
+    private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
+        @Override
+        public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
+
+        }
+    };
+
+    private ContextHubManager(Context context) {
+        checkPermissions();
+        mContext = context;
+        mContextHubConnected = false;
+    }
+
+    private ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mContextHubService = IContextHubService.Stub.asInterface(service);
+            mContextHubConnected = true;
+
+            // Register our Callback
+            try {
+                mContextHubService.registerCallBack(mClientCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not register callback with context hub service :" + e.toString());
+            }
+            Log.d(TAG, "contexthub manager connected to " + name.toString());
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mContextHubService = null;
+            mContextHubConnected = false;
+            Log.d(TAG, "contexthub manager disconnected from " + name.toString());
+        }
+    };
+
+}
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
new file mode 100644
index 0000000..915f1ec
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubMessage;
+
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
new file mode 100644
index 0000000..954e97d
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubMessage {
+    private int mType;
+    private int mVersion;
+    private byte[]mData;
+
+    /**
+     * Get the message type
+     *
+     * @return int - message type
+     */
+    public int getMsgType() {
+        return mType;
+    }
+
+    /**
+     * get message version
+     *
+     * @return int - message version
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * get message data
+     *
+     * @return byte[] - message data buffer
+     */
+    public byte[] getData() {
+        return Arrays.copyOf(mData, mData.length);
+    }
+
+    /**
+     * set message type
+     *
+     * @param msgType - message type
+     */
+    public void setMsgType(int msgType) {
+        mType = msgType;
+    }
+
+    /**
+     * Set message version
+     *
+     * @param version - message version
+     */
+    public void setVersion(int version) {
+        mVersion = version;
+    }
+
+    /**
+     * set message data
+     *
+     * @param data - message buffer
+     */
+    public void setMsgData(byte[] data) {
+        mData = Arrays.copyOf(data, data.length);
+    }
+
+    /**
+     * Constructor for a context hub message
+     *
+     * @param msgType - message type
+     * @param version - version
+     * @param data    - message buffer
+     */
+    public ContextHubMessage(int msgType, int version, byte[] data) {
+        mType = msgType;
+        mVersion = version;
+        mData = Arrays.copyOf(data, data.length);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    private ContextHubMessage(Parcel in) {
+        mType = in.readInt();
+        mVersion = in.readInt();
+        byte[] byteBuffer = new byte[in.readInt()];
+        in.readByteArray(byteBuffer);
+    }
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mType);
+        out.writeInt(mVersion);
+        out.writeInt(mData.length);
+        out.writeByteArray(mData);
+    }
+
+    public static final Parcelable.Creator<ContextHubMessage> CREATOR
+            = new Parcelable.Creator<ContextHubMessage>() {
+        public ContextHubMessage createFromParcel(Parcel in) {
+            return new ContextHubMessage(in);
+        }
+
+        public ContextHubMessage[] newArray(int size) {
+            return new ContextHubMessage[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
new file mode 100644
index 0000000..a2a13c6
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class ContextHubService extends Service {
+
+    private static final String TAG = "ContextHubService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static ContextHubService sSingletonInstance;
+    private static final Object sSingletonInstanceLock = new Object();
+
+    private HashMap<Integer, ContextHubInfo> mHubHash;
+    private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
+    private ContextHubInfo[] mContexthubInfo;
+
+
+    private native int nativeSendMessage(int[] header, byte[] data);
+    private native ContextHubInfo[] nativeInitialize();
+
+    private int onMessageReceipt(int[] header, byte[] data) {
+        return 0;
+    }
+    private void initialize() {
+        mContexthubInfo = nativeInitialize();
+
+        mHubHash = new HashMap<Integer, ContextHubInfo>();
+
+        for (int i = 0; i < mContexthubInfo.length; i++) {
+            mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+        }
+    }
+
+    private ContextHubService(Context context) {
+        initialize();
+        Log.d(TAG, "Created from " + context.toString());
+    }
+
+    public static ContextHubService getInstance(Context context) {
+        synchronized (sSingletonInstanceLock) {
+            if (sSingletonInstance == null) {
+                sSingletonInstance = new ContextHubService(context);
+            }
+            return sSingletonInstance;
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+
+        private  IContextHubCallback callback;
+
+        @Override
+        public int registerCallBack(IContextHubCallback callback) throws RemoteException{
+            this.callback = callback;
+            return 0;
+        }
+
+        @Override
+        public int[] getContextHubHandles() throws RemoteException {
+            int [] returnArray = new int[mHubHash.size()];
+            int i = 0;
+            for (int key : mHubHash.keySet()) {
+                // Add any filtering here
+                returnArray[i] = key;
+                i++;
+            }
+            return returnArray;
+        }
+
+        @Override
+        public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
+            return mHubHash.get(contexthubHandle);
+        }
+
+        @Override
+        public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
+            if (!mHubHash.containsKey(hubHandle)) {
+                return -1;
+            } else {
+                // Call Native interface here
+                int[] msgHeader = new int[8];
+                msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
+                msgHeader[1] = app.getAppId();
+                msgHeader[2] = app.getAppVersion();
+                msgHeader[3] = 0; // LOADING_HINTS
+                msgHeader[4] = hubHandle;
+
+                int handle = nativeSendMessage(msgHeader, app.getAppBinary());
+
+                // if successful, add an entry to mNanoAppHash
+
+                if(handle > 0) {
+                    return 0;
+                } else {
+
+                    return -1;
+                }
+            }
+        }
+
+        @Override
+        public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+                return -1;
+            } else {
+                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+                // Call Native interface here
+                int[] msgHeader = new int[8];
+                msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
+                msgHeader[1] = info.getContexthubId();
+                msgHeader[2] = info.getHandle();
+
+                int result = nativeSendMessage(msgHeader, null);
+                // if successful, remove the entry in mNanoAppHash
+                if(result == 0) {
+                    mNanoAppHash.remove(nanoAppInstanceHandle);
+                }
+                return(result);
+            }
+        }
+
+        @Override
+        public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+            // This assumes that all the nanoAppInfo is current. This is reasonable
+            // for the use cases for tightly controlled nanoApps.
+            //
+            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+                return(mNanoAppHash.get(nanoAppInstanceHandle));
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+            ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+            for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+                if(filter.testMatch(info)){
+                    foundInstances.add(nanoAppInstance);
+                }
+            }
+
+            int[] retArray = new int[foundInstances.size()];
+            for (int i = 0; i < foundInstances.size(); i++) {
+                retArray[i] = foundInstances.get(i).intValue();
+            }
+
+            return retArray;
+        }
+
+        @Override
+        public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+            int[] msgHeader = new int[8];
+            msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
+            msgHeader[1] = hubHandle;
+            msgHeader[2] = nanoAppHandle;
+            msgHeader[3] = msg.getMsgType();
+            msgHeader[4] = msg.getVersion();
+
+            return (nativeSendMessage(msgHeader, msg.getData()));
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
new file mode 100644
index 0000000..45b1ef4
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.ContextHubMessage;
+
+/** @hide */
+oneway interface IContextHubCallback {
+    void onMessageReceipt(int hubId, int nanoAppId, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
new file mode 100644
index 0000000..b2db0b2
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+// Declare any non-default types here with import statements
+import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubCallback;
+
+/** @hide */
+interface IContextHubService {
+
+    // register a callback to receive messages
+    int registerCallBack(in IContextHubCallback callback);
+
+    // Gets a list of available context hub handles
+    int[] getContextHubHandles();
+
+    // Get the properties of a hub
+    ContextHubInfo getContextHubInfo(int contextHubHandle);
+
+    // Load a nanoapp on a specified context hub
+    int loadNanoApp(int hubHandle, in NanoApp app);
+
+    // Unload a nanoapp instance
+    int unloadNanoApp(int nanoAppInstanceHandle);
+
+    // get information about a nanoAppInstance
+    NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
+
+    // find all nanoApp instances matching some filter
+    int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
+
+    // send a message to a nanoApp
+    int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
new file mode 100644
index 0000000..e8c7615
--- /dev/null
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+
+@SystemApi
+public class MemoryRegion implements Parcelable{
+
+    private int mSizeBytes;
+    private int mSizeBytesFree;
+    private boolean mIsReadable;
+    private boolean mIsWritable;
+    private boolean mIsExecutable;
+
+    /**
+     * get the capacity of the memory region in bytes
+     *
+     * @return int - the memory capacity in bytes
+     */
+    public int getCapacityBytes() {
+        return mSizeBytes;
+    }
+
+    /**
+     * get the free capacity of the memory region in bytes
+     *
+     * @return int - free bytes
+     */
+    public int getFreeCapacityBytes() {
+        return mSizeBytesFree;
+    }
+
+    /**
+     * Is the memory readable
+     *
+     * @return boolean - true if memory is readable, false otherwise
+     */
+    public boolean isReadable() {
+        return mIsReadable;
+    }
+
+    /**
+     * Is the memory writable
+     *
+     * @return boolean - true if memory is writable, false otherwise
+     */
+    public boolean isWritable() {
+        return mIsWritable;
+    }
+
+    /**
+     * Is the memory executable
+     *
+     * @return boolean - true if memory is executable, false
+     *         otherwise
+     */
+    public boolean isExecutable() {
+        return mIsExecutable;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSizeBytes);
+        dest.writeInt(mSizeBytesFree);
+        dest.writeInt(mIsReadable ? 1 : 0);
+        dest.writeInt(mIsWritable ? 1 : 0);
+        dest.writeInt(mIsExecutable ? 1 : 0);
+    }
+
+    public MemoryRegion(Parcel source) {
+        mSizeBytes = source.readInt();
+        mSizeBytesFree = source.readInt();
+        mIsReadable = source.readInt() != 0;
+        mIsWritable = source.readInt() != 0;
+        mIsExecutable = source.readInt() != 0;
+    }
+
+    public static final Parcelable.Creator<MemoryRegion> CREATOR
+            = new Parcelable.Creator<MemoryRegion>() {
+        public MemoryRegion createFromParcel(Parcel in) {
+            return new MemoryRegion(in);
+        }
+
+        public MemoryRegion[] newArray(int size) {
+            return new MemoryRegion[size];
+        }
+    };
+
+}
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
new file mode 100644
index 0000000..d32c44a
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
new file mode 100644
index 0000000..36d181f
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class describing nano apps.
+ * A nano app is a piece of executable code that can be
+ * downloaded onto a specific architecture. These are targtted
+ * for low power compute domains on a device.
+ *
+ * Nano apps are expected to be used only by bundled apps only
+ * at this time.
+ *
+ * @hide
+ */
+@SystemApi
+public class NanoApp {
+    private String mPublisher;
+    private String mName;
+
+    private int mAppId;
+    private int mAppVersion;
+
+    private int mNeededReadMemBytes;
+    private int mNeededWriteMemBytes;
+    private int mNeededExecMemBytes;
+
+    private int[] mNeededSensors;
+    private int[] mOutputEvents;
+    private byte[] mAppBinary;
+
+    public NanoApp() {
+    }
+
+    /**
+     * Set the publisher name
+     *
+     * @param publisher name of the publisher of this nano app
+     */
+    public void setPublisher(String publisher) {
+        mPublisher = publisher;
+    }
+
+    /**
+     * set the name of the app
+     *
+     * @param name   name of the app
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * set the app identifier
+     *
+     * @param appId  add identifier
+     */
+    public void setAppId(int appId) {
+        mAppId = appId;
+    }
+
+    /**
+     * Set the app version
+     *
+     * @param appVersion app version
+     */
+    public void setAppVersion(int appVersion) {
+        mAppVersion = appVersion;
+    }
+
+    /**
+     * set memory needed as read only
+     *
+     * @param neededReadMemBytes
+     *               read only memory needed in bytes
+     */
+    public void setNeededReadMemBytes(int neededReadMemBytes) {
+        mNeededReadMemBytes = neededReadMemBytes;
+    }
+
+    /**
+     * set writable memory needed in bytes
+     *
+     * @param neededWriteMemBytes
+     *               writable memory needed in bytes
+     */
+    public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+        mNeededWriteMemBytes = neededWriteMemBytes;
+    }
+
+    /**
+     * set executable memory needed
+     *
+     * @param neededExecMemBytes
+     *               executable memory needed in bytes
+     */
+    public void setNeededExecMemBytes(int neededExecMemBytes) {
+        mNeededExecMemBytes = neededExecMemBytes;
+    }
+
+    /**
+     * set the sensors needed for this app
+     *
+     * @param neededSensors
+     *               needed Sensors
+     */
+    public void setNeededSensors(int[] neededSensors) {
+        mNeededSensors = neededSensors;
+    }
+
+    public void setOutputEvents(int[] outputEvents) {
+        mOutputEvents = outputEvents;
+    }
+
+    /**
+     * set output events returned by the nano app
+     *
+     * @param appBinary generated events
+     */
+    public void setAppBinary(byte[] appBinary) {
+        mAppBinary = appBinary;
+    }
+
+
+    /**
+     * get the publisher name
+     *
+     * @return publisher name
+     */
+    public String getPublisher() {
+      return mPublisher;
+    }
+
+    /**
+     * get the name of the app
+     *
+     * @return app name
+     */
+    public String getName() {
+    return mName;
+    }
+
+    /**
+     * get the identifier of the app
+     *
+     * @return identifier for this app
+     */
+    public int getAppId() {
+      return mAppId;
+    }
+
+    /**
+     * get the app version
+     *
+     * @return app version
+     */
+    public int getAppVersion() {
+      return mAppVersion;
+    }
+
+    /**
+     * get the ammount of readable memory needed by this app
+     *
+     * @return readable memory needed in bytes
+     */
+    public int getNeededReadMemBytes() {
+      return mNeededReadMemBytes;
+    }
+
+    /**
+     * get the ammount og writable memory needed in bytes
+     *
+     * @return writable memory needed in bytes
+     */
+    public int getNeededWriteMemBytes() {
+      return mNeededWriteMemBytes;
+    }
+
+    /**
+     * executable memory needed in bytes
+     *
+     * @return executable memory needed in bytes
+     */
+    public int getNeededExecMemBytes() {
+      return mNeededExecMemBytes;
+    }
+
+    /**
+     * get the sensors needed by this app
+     *
+     * @return sensors needed
+     */
+    public int[] getNeededSensors() {
+      return mNeededSensors;
+    }
+
+    /**
+     * get the events generated by this app
+     *
+     * @return generated events
+     */
+    public int[] getOutputEvents() {
+      return mOutputEvents;
+    }
+
+    /**
+     * get the binary for this app
+     *
+     * @return app binary
+     */
+    public byte[] getAppBinary() {
+      return mAppBinary;
+    }
+
+    private NanoApp(Parcel in) {
+        mPublisher = in.readString();
+        mName = in.readString();
+
+        mAppId = in.readInt();
+        mAppVersion = in.readInt();
+        mNeededReadMemBytes = in.readInt();
+        mNeededWriteMemBytes = in.readInt();
+        mNeededExecMemBytes = in.readInt();
+
+        int mNeededSensorsLength = in.readInt();
+        mNeededSensors = new int[mNeededSensorsLength];
+        in.readIntArray(mNeededSensors);
+
+        int mOutputEventsLength = in.readInt();
+        mOutputEvents = new int[mOutputEventsLength];
+        in.readIntArray(mOutputEvents);
+
+        int binaryLength = in.readInt();
+        mAppBinary = new byte[binaryLength];
+        in.readByteArray(mAppBinary);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPublisher);
+        out.writeString(mName);
+        out.writeInt(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mNeededReadMemBytes);
+        out.writeInt(mNeededWriteMemBytes);
+        out.writeInt(mNeededExecMemBytes);
+
+        out.writeInt(mNeededSensors.length);
+        out.writeIntArray(mNeededSensors);
+
+        out.writeInt(mOutputEvents.length);
+        out.writeIntArray(mOutputEvents);
+
+        out.writeInt(mAppBinary.length);
+        out.writeByteArray(mAppBinary);
+    }
+
+    public static final Parcelable.Creator<NanoApp> CREATOR
+            = new Parcelable.Creator<NanoApp>() {
+        public NanoApp createFromParcel(Parcel in) {
+            return new NanoApp(in);
+        }
+
+        public NanoApp[] newArray(int size) {
+            return new NanoApp[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
new file mode 100644
index 0000000..cc6d475
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
new file mode 100644
index 0000000..ac341e4
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppFilter {
+
+    // The appId, can be set to APP_ID_ANY
+    private long mAppId;
+
+    // Version to filter apps
+    private int mAppVersion;
+
+    // filtering spec for version
+    private int mVersionRestrictionMask;
+
+    // If APP_ID is any, then a match is performef with the vendor mask
+    private long mAppIdVendorMask;
+
+    // Id of the context hub this instance is expected on
+    private int mContextHubId;
+
+    /**
+     * Flag indicating any version. With this flag set, all versions shall match provided version.
+     */
+    public static final int FLAGS_VERSION_ANY = -1;
+    /**
+     * If this flag is set, only versions strictly greater than the version specified shall match.
+     */
+    public static final int FLAGS_VERSION_GREAT_THAN  = 2;
+    /**
+     * If this flag is set, only versions strictly less than the version specified shall match.
+     */
+    public static final int FLAGS_VERSION_LESS_THAN   = 4;
+    public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
+
+    /**
+     * If this flag is set, only versions strictly equal to the version specified shall match.
+     */
+    public static final int APP_ANY = -1;
+
+    /**
+     * If this flag is set, all vendors shall match.
+     */
+    public static final int VENDOR_ANY = -1;
+
+    /**
+     * If this flag is set, any hub shall match.
+     */
+    public static final int HUB_ANY = -1;
+
+    private NanoAppFilter(Parcel in) {
+        mAppId = in.readLong();
+        mAppVersion = in.readInt();
+        mVersionRestrictionMask = in.readInt();
+        mAppIdVendorMask = in.readInt();
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+
+        out.writeLong(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mVersionRestrictionMask);
+        out.writeLong(mAppIdVendorMask);
+    }
+
+    /**
+     * Create a filter
+     *
+     * @param appId       application id
+     * @param appVersion  application version
+     * @param versionMask version
+     * @param vendorMask  vendor
+     */
+    public NanoAppFilter(long appId, int appVersion, int versionMask, long vendorMask) {
+        mAppId = appId;
+        mAppVersion = appVersion;
+        mVersionRestrictionMask = versionMask;
+        mAppIdVendorMask = vendorMask;
+    }
+
+    private boolean versionsMatch(int versionRestrictionMask, int expected, int actual){
+        // some refactoring of version restriction mask is needed, until then, return all
+        return true;
+    }
+    /**
+     *
+     * @param nano app instance info
+     *
+     * @return true if this is a match, false otherwise
+     */
+    public boolean testMatch(NanoAppInstanceInfo info) {
+        if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+                (mAppId == APP_ANY || info.getAppId() == mAppId) &&
+               // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
+                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static final Parcelable.Creator<NanoAppFilter> CREATOR
+            = new Parcelable.Creator<NanoAppFilter>() {
+        public NanoAppFilter createFromParcel(Parcel in) {
+            return new NanoAppFilter(in);
+        }
+
+        public NanoAppFilter[] newArray(int size) {
+            return new NanoAppFilter[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
new file mode 100644
index 0000000..c8c40d7
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppInstanceInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
new file mode 100644
index 0000000..ac62919
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppInstanceInfo {
+    private String mPublisher;
+    private String mName;
+
+    private int mAppId;
+    private int mAppVersion;
+
+    private int mNeededReadMemBytes;
+    private int mNeededWriteMemBytes;
+    private int mNeededExecMemBytes;
+
+    private int[] mNeededSensors;
+    private int[] mOutputEvents;
+
+    private int mContexthubId;
+    private int mHandle;
+
+    public NanoAppInstanceInfo() {
+    }
+
+    /**
+     * get the publisher of this app
+     *
+     * @return String - name of the publisher
+     */
+    public String getPublisher() {
+        return mPublisher;
+    }
+
+
+    /**
+     * set the publisher name for the app
+     *
+     * @param publisher - name of the publisher
+     */
+    public void setPublisher(String publisher) {
+        mPublisher = publisher;
+    }
+
+    /**
+     * get the name of the app
+     *
+     * @return String - name of the app
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * set the name of the app
+     *
+     * @param name - name of the app
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * Get the application identifier
+     *
+     * @return int - application identifier
+     */
+    public int getAppId() {
+        return mAppId;
+    }
+
+    /**
+     * Set the application identifier
+     *
+     * @param appId - application identifier
+     */
+    public void setAppId(int appId) {
+        mAppId = appId;
+    }
+
+    /**
+     * Set the application version
+     *
+     * @return int - version of the app
+     */
+    public int getAppVersion() {
+        return mAppVersion;
+    }
+
+    /**
+     * Set the application version
+     *
+     * @param appVersion - version of the app
+     */
+    public void setAppVersion(int appVersion) {
+        mAppVersion = appVersion;
+    }
+
+    /**
+     * Get the read memory needed by the app
+     *
+     * @return int - readable memory needed in bytes
+     */
+    public int getNeededReadMemBytes() {
+        return mNeededReadMemBytes;
+    }
+
+    /**
+     * Set the read memory needed by the app
+     *
+     * @param neededReadMemBytes - readable Memory needed in bytes
+     */
+    public void setNeededReadMemBytes(int neededReadMemBytes) {
+        mNeededReadMemBytes = neededReadMemBytes;
+    }
+
+    /**
+     *  get writable memory needed by the app
+     *
+     * @return int - writable memory needed by the app
+     */
+    public int getNeededWriteMemBytes() {
+        return mNeededWriteMemBytes;
+    }
+
+    /**
+     * set writable memory needed by the app
+     *
+     * @param neededWriteMemBytes - writable memory needed by the
+     *                            app
+     */
+    public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+        mNeededWriteMemBytes = neededWriteMemBytes;
+    }
+
+    /**
+     * get executable memory needed by the app
+     *
+     * @return int - executable memory needed by the app
+     */
+    public int getNeededExecMemBytes() {
+        return mNeededExecMemBytes;
+    }
+
+    /**
+     * set executable memory needed by the app
+     *
+     * @param neededExecMemBytes - executable memory needed by the
+     *                           app
+     */
+    public void setNeededExecMemBytes(int neededExecMemBytes) {
+        mNeededExecMemBytes = neededExecMemBytes;
+    }
+
+    /**
+     * Get the sensors needed by this app
+     *
+     * @return int[] all the required sensors needed by this app
+     */
+    public int[] getNeededSensors() {
+        return mNeededSensors;
+    }
+
+    /**
+     * set the sensors needed by this app
+     *
+     * @param neededSensors - all the sensors needed by this app
+     */
+    public void setNeededSensors(int[] neededSensors) {
+        mNeededSensors = neededSensors;
+    }
+
+    /**
+     * get the events generated by this app
+     *
+     * @return all the events that can be generated by this app
+     */
+    public int[] getOutputEvents() {
+        return mOutputEvents;
+    }
+
+    /**
+     * set the output events that can be generated by this app
+     *
+     * @param outputEvents - the events that may be generated by
+     *                     this app
+     */
+    public void setOutputEvents(int[] outputEvents) {
+        mOutputEvents = outputEvents;
+    }
+
+    /**
+     * get the context hub identifier
+     *
+     * @return int - system unique hub identifier
+     */
+    public int getContexthubId() {
+        return mContexthubId;
+    }
+
+    /**
+     * set the context hub identifier
+     *
+     * @param contexthubId - system wide unique identifier
+     */
+    public void setContexthubId(int contexthubId) {
+        mContexthubId = contexthubId;
+    }
+
+    /**
+     * get a handle to the nano app instance
+     *
+     * @return int - handle to this instance
+     */
+    public int getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * set the handle for an app instance
+     *
+     * @param handle - handle to this instance
+     */
+    public void setHandle(int handle) {
+        mHandle = handle;
+    }
+
+
+    private NanoAppInstanceInfo(Parcel in) {
+        mPublisher = in.readString();
+        mName = in.readString();
+
+        mAppId = in.readInt();
+        mAppVersion = in.readInt();
+        mNeededReadMemBytes = in.readInt();
+        mNeededWriteMemBytes = in.readInt();
+        mNeededExecMemBytes = in.readInt();
+
+        int mNeededSensorsLength = in.readInt();
+        mNeededSensors = new int[mNeededSensorsLength];
+        in.readIntArray(mNeededSensors);
+
+        int mOutputEventsLength = in.readInt();
+        mOutputEvents = new int[mOutputEventsLength];
+        in.readIntArray(mOutputEvents);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPublisher);
+        out.writeString(mName);
+        out.writeInt(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mContexthubId);
+        out.writeInt(mNeededReadMemBytes);
+        out.writeInt(mNeededWriteMemBytes);
+        out.writeInt(mNeededExecMemBytes);
+
+        out.writeInt(mNeededSensors.length);
+        out.writeIntArray(mNeededSensors);
+
+        out.writeInt(mOutputEvents.length);
+        out.writeIntArray(mOutputEvents);
+
+    }
+
+    public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
+            = new Parcelable.Creator<NanoAppInstanceInfo>() {
+        public NanoAppInstanceInfo createFromParcel(Parcel in) {
+            return new NanoAppInstanceInfo(in);
+        }
+
+        public NanoAppInstanceInfo[] newArray(int size) {
+            return new NanoAppInstanceInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index bcc1213..344d06e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -144,6 +144,7 @@
     }
 
     /** @hide */
+    @SystemApi
     public static UserHandle of(@UserIdInt int userId) {
         return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
     }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6321122..1ac798b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1382,7 +1382,7 @@
     /**
      * Returns information for all users on this device.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @return the list of users that were created.
+     * @return the list of users that exist on the device.
      * @hide
      */
     public List<UserInfo> getUsers() {
@@ -1395,6 +1395,29 @@
     }
 
     /**
+     * Returns serial numbers of all users on this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param excludeDying specify if the list should exclude users being removed.
+     * @return the list of serial numbers of users that exist on the device.
+     * @hide
+     */
+    @SystemApi
+    public long[] getSerialNumbersOfUsers(boolean excludeDying) {
+        try {
+            List<UserInfo> users = mService.getUsers(excludeDying);
+            long[] result = new long[users.size()];
+            for (int i = 0; i < result.length; i++) {
+                result[i] = users.get(i).serialNumber;
+            }
+            return result;
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get users list", re);
+            return null;
+        }
+    }
+
+    /**
      * @return the user's account name, null if not found.
      * @hide
      */
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fda6326..ebb12fd 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.SystemApi;
 import android.annotation.XmlRes;
 import android.app.Activity;
 import android.content.Context;
@@ -24,8 +25,8 @@
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.util.Log;
@@ -110,7 +111,13 @@
      * managed by this instance.
      */
     private int mSharedPreferencesMode;
-    
+
+    private static final int STORAGE_DEFAULT = 0;
+    private static final int STORAGE_DEVICE_ENCRYPTED = 1;
+    private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
+
+    private int mStorage = STORAGE_DEFAULT;
+
     /**
      * The {@link PreferenceScreen} at the root of the preference hierarchy.
      */
@@ -343,6 +350,46 @@
     }
 
     /**
+     * Sets the storage location used internally by this class to be the default
+     * provided by the hosting {@link Context}.
+     */
+    public void setStorageDefault() {
+        mStorage = STORAGE_DEFAULT;
+        mSharedPreferences = null;
+    }
+
+    /**
+     * Explicitly set the storage location used internally by this class to be
+     * device-encrypted storage.
+     * <p>
+     * Data stored in device-encrypted storage is typically encrypted with a key
+     * tied to the physical device, and it can be accessed when the device has
+     * booted successfully, both <em>before and after</em> the user has
+     * authenticated with their credentials (such as a lock pattern or PIN).
+     * Because device-encrypted data is available before user authentication,
+     * you should carefully consider what data you store using this mode.
+     *
+     * @see Context#createDeviceEncryptedStorageContext()
+     */
+    public void setStorageDeviceEncrypted() {
+        mStorage = STORAGE_DEVICE_ENCRYPTED;
+        mSharedPreferences = null;
+    }
+
+    /**
+     * Explicitly set the storage location used internally by this class to be
+     * credential-encrypted storage.
+     *
+     * @see Context#createCredentialEncryptedStorageContext()
+     * @hide
+     */
+    @SystemApi
+    public void setStorageCredentialEncrypted() {
+        mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+        mSharedPreferences = null;
+    }
+
+    /**
      * Gets a SharedPreferences instance that preferences managed by this will
      * use.
      * 
@@ -351,7 +398,20 @@
      */
     public SharedPreferences getSharedPreferences() {
         if (mSharedPreferences == null) {
-            mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+            final Context storageContext;
+            switch (mStorage) {
+                case STORAGE_DEVICE_ENCRYPTED:
+                    storageContext = mContext.createDeviceEncryptedStorageContext();
+                    break;
+                case STORAGE_CREDENTIAL_ENCRYPTED:
+                    storageContext = mContext.createCredentialEncryptedStorageContext();
+                    break;
+                default:
+                    storageContext = mContext;
+                    break;
+            }
+
+            mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
                     mSharedPreferencesMode);
         }
         
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc0d7d6..c9c0cde 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -501,6 +501,23 @@
             "android.settings.USER_DICTIONARY_SETTINGS";
 
     /**
+     * Activity Action: Show settings to configure the hardware keyboard layout.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     *
+     * @see android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_KEYBOARD_LAYOUT_SETTINGS =
+            "android.settings.KEYBOARD_LAYOUT_SETTINGS";
+
+    /**
      * Activity Action: Adds a word to the user dictionary.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 772eeec..0c5a5fc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -589,14 +589,14 @@
         public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
 
         /**
-         * Window type: Windows that are overlaid <em>only</em> by an {@link
+         * Window type: Windows that are overlaid <em>only</em> by a connected {@link
          * android.accessibilityservice.AccessibilityService} for interception of
          * user interactions without changing the windows an accessibility service
          * can introspect. In particular, an accessibility service can introspect
          * only windows that a sighted user can interact with which is they can touch
          * these windows or can type into these windows. For example, if there
          * is a full screen accessibility overlay that is touchable, the windows
-         * below it will be introspectable by an accessibility service regardless
+         * below it will be introspectable by an accessibility service even though
          * they are covered by a touchable window.
          */
         public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1327ea1..b673386 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -38,8 +38,8 @@
 /**
  * This class represents a node of the window content as well as actions that
  * can be requested from its source. From the point of view of an
- * {@link android.accessibilityservice.AccessibilityService} a window content is
- * presented as tree of accessibility node info which may or may not map one-to-one
+ * {@link android.accessibilityservice.AccessibilityService} a window's content is
+ * presented as a tree of accessibility node infos, which may or may not map one-to-one
  * to the view hierarchy. In other words, a custom view is free to report itself as
  * a tree of accessibility node info.
  * </p>
@@ -50,7 +50,7 @@
  * <p>
  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
  * details about how to obtain a handle to window content as a tree of accessibility
- * node info as well as familiarizing with the security model.
+ * node info as well as details about the security model.
  * </p>
  * <div class="special reference">
  * <h3>Developer Guides</h3>
@@ -2422,18 +2422,30 @@
     }
 
     /**
-     * Gets the text selection start.
+     * Gets the text selection start or the cursor position.
+     * <p>
+     * If no text is selected, both this method and
+     * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
+     * the current location of the cursor.
+     * </p>
      *
-     * @return The text selection start if there is selection or -1.
+     * @return The text selection start, the cursor location if there is no selection, or -1 if
+     *         there is no text selection and no cursor.
      */
     public int getTextSelectionStart() {
         return mTextSelectionStart;
     }
 
     /**
-     * Gets the text selection end.
+     * Gets the text selection end if text is selected.
+     * <p>
+     * If no text is selected, both this method and
+     * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
+     * the current location of the cursor.
+     * </p>
      *
-     * @return The text selection end if there is selection or -1.
+     * @return The text selection end, the cursor location if there is no selection, or -1 if
+     *         there is no text selection and no cursor.
      */
     public int getTextSelectionEnd() {
         return mTextSelectionEnd;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 4d4acb9..1cf15ac 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -201,7 +201,6 @@
         needsFill = true;
     } else if (mFillColor != SK_ColorTRANSPARENT) {
         mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
-        outCanvas->drawPath(renderPath, mPaint);
         needsFill = true;
     }
 
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 025133f..3b892cb 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -150,4 +150,8 @@
     mJavaObjStatus = UNKNOWN_ERROR;
 }
 
+uint32_t JMediaDataSource::getFlags() {
+    return 0;
+}
+
 }  // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 2bc237e..34624eb 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -45,6 +45,7 @@
     virtual ssize_t readAt(off64_t offset, size_t size);
     virtual status_t getSize(off64_t* size);
     virtual void close();
+    virtual uint32_t getFlags();
 
 private:
     // Protect all member variables with mLock because this object will be
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index ad567d3..210682f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.UserInfo;
 import android.graphics.Color;
@@ -227,6 +228,26 @@
     }
 
     /**
+     * Check if an application is suspended.
+     *
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} if the application is not suspended.
+     */
+    public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
+            int userId) {
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        try {
+            ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
+            if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+                return getProfileOrDeviceOwnerOnCallingUser(context);
+            }
+        } catch (RemoteException e) {
+            // Nothing to do
+        }
+        return null;
+    }
+
+    /**
      * Check if account management for a specific type of account is disabled by admin.
      * Only a profile or device owner can disable account management. So, we check if account
      * management is disabled and return profile or device owner on the calling user.
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index e4d0fec..88313bb 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -12,6 +12,7 @@
     android-support-v7-preference \
     android-support-v7-appcompat \
     android-support-v14-preference \
+    android-support-v17-leanback \
     framework-protos
 
 LOCAL_JAVA_LIBRARIES := telephony-common
@@ -30,10 +31,12 @@
     frameworks/support/v7/preference/res \
     frameworks/support/v14/preference/res \
     frameworks/support/v7/appcompat/res \
-    frameworks/support/v7/recyclerview/res
+    frameworks/support/v7/recyclerview/res \
+    frameworks/support/v17/leanback/res
 
 LOCAL_AAPT_FLAGS := --auto-add-overlay \
-    --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat
+    --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
+    --extra-packages android.support.v17.leanback
 
 ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 21abb90..2713fb5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -236,6 +236,20 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".recents.tv.RecentsTvActivity"
+                  android:label="@string/accessibility_desc_recent_apps"
+                  android:exported="false"
+                  android:launchMode="singleInstance"
+                  android:excludeFromRecents="true"
+                  android:stateNotNeeded="true"
+                  android:resumeWhilePausing="true"
+                  android:screenOrientation="behind"
+                  android:theme="@style/RecentsTheme.Wallpaper">
+            <intent-filter>
+                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+            </intent-filter>
+        </activity>
+
         <!-- Callback for dismissing screenshot notification after a share target is picked -->
         <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
                   android:process=":screenshot"
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
new file mode 100644
index 0000000..b4543bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.RecentsTvView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/recents_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false" >
+
+    <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
+        android:id="@+id/task_list"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:descendantFocusability="beforeDescendants"
+        android:gravity="center"
+        android:paddingStart="@dimen/recents_tv_grid_row_padding"
+        android:paddingEnd="@dimen/recents_tv_grid_row_padding"
+        android:focusable="true"/>
+
+</com.android.systemui.recents.tv.views.RecentsTvView>
+
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
new file mode 100644
index 0000000..fa1daad
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_card_view.xml
@@ -0,0 +1,77 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:layout_gravity="center"
+    android:layout_centerInParent="true">
+
+    <RelativeLayout
+            android:layout_width="@dimen/recents_tv_card_width"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:layout_gravity="center">
+        <ImageView
+                android:id="@+id/card_view_thumbnail"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/recents_tv_card_height"
+                android:scaleType="centerCrop"
+                android:gravity="center"
+                android:layout_alignParentTop="true"
+                android:layout_centerHorizontal="true"/>
+
+        <RelativeLayout
+                android:id="@+id/card_info_field"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/card_view_thumbnail"
+                android:background="@color/recents_tv_card_background_color" >
+            <TextView
+                    android:id="@+id/card_title_text"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentTop="false"
+                    android:includeFontPadding="true"
+                    android:minLines="1"
+                    android:maxLines="2"
+                    android:textColor="@color/recents_tv_card_title_text_color"
+                    android:ellipsize="end" />
+            <TextView
+                    android:id="@+id/card_content_text"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentStart="true"
+                    android:layout_below="@id/card_title_text"
+                    android:includeFontPadding="true"
+                    android:minLines="1"
+                    android:maxLines="2"
+                    android:textColor="@color/recents_tv_card_content_text_color"
+                    android:ellipsize="end" />
+            <ImageView
+                    android:id="@+id/card_extra_badge"
+                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+                    android:scaleType="fitCenter"
+                    android:background="@android:color/transparent"
+                    android:contentDescription="@null"
+                    android:layout_centerVertical="true"
+                    android:layout_alignParentRight="true"/>
+        </RelativeLayout>
+    </RelativeLayout>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 955efb5..19bc755 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -28,9 +28,6 @@
     <declare-styleable name="NotificationLinearLayout">
         <attr name="insetLeft" format="dimension" />
     </declare-styleable>
-    <declare-styleable name="NotificationRowLayout">
-        <attr name="rowHeight" format="dimension" />
-    </declare-styleable>
     <declare-styleable name="RecentsPanelView">
         <attr name="recentItemLayout" format="reference" />
     </declare-styleable>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
new file mode 100644
index 0000000..6f4c983
--- /dev/null
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 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.
+ */
+-->
+<resources>
+    <color name="recents_tv_card_background_color">#FF37474F</color>
+    <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
+    <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
+    <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8b0350a..32d09e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,5 +606,4 @@
 
     <dimen name="docked_divider_handle_width">16dp</dimen>
     <dimen name="docked_divider_handle_height">2dp</dimen>
-
 </resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..77605bd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 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.
+ */
+-->
+<resources>
+    <!-- Dimens for recents card in the recents view on tv -->
+    <dimen name="recents_tv_card_width">150dip</dimen>
+    <dimen name="recents_tv_card_height">85dip</dimen>
+    <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+
+    <!-- Padding for grid view in recents view on tv -->
+    <dimen name="recents_tv_grid_row_padding">56dip</dimen>
+    <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
+    <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
+    <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+
+    <!-- Values for focus animation -->
+    <dimen name="recents_tv_unselected_item_z">6dp</dimen>
+    <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
new file mode 100644
index 0000000..bfd8f8b
--- /dev/null
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources>
+    <integer name="item_scale_anim_duration">150</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
new file mode 100644
index 0000000..45cdc07
--- /dev/null
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <item format="float" type="raw" name="unselected_scale">1.0</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 27d4c0e..c7e5ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -35,6 +35,10 @@
 public class HumanInteractionClassifier extends Classifier {
     private static final String HIC_ENABLE = "HIC_enable";
     private static final float FINGER_DISTANCE = 0.1f;
+
+    /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
+    private static final int HIC_ENABLE_DEFAULT = 1;
+
     private static HumanInteractionClassifier sInstance = null;
 
     private final Handler mHandler = new Handler();
@@ -101,9 +105,9 @@
     }
 
     private void updateConfiguration() {
-        mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+        mEnableClassifier = 0 != Settings.Global.getInt(
                 mContext.getContentResolver(),
-                HIC_ENABLE, 0);
+                HIC_ENABLE, HIC_ENABLE_DEFAULT);
     }
 
     public void setType(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 789e72e..35000d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs;
 
+import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -23,7 +24,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
@@ -271,7 +271,7 @@
 
     protected void checkIfRestrictionEnforced(State state, String userRestriction) {
         EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
-                userRestriction, UserHandle.myUserId());
+                userRestriction, ActivityManager.getCurrentUser());
         if (admin != null) {
             state.disabledByPolicy = true;
             state.enforcedAdmin = admin;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 6a07a07..dbb7423f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,10 @@
 
     @Override
     protected void handleClick() {
+        if (!mController.canConfigBluetooth()) {
+            mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+            return;
+        }
         if (!mState.value) {
             mState.value = true;
             mController.setBluetoothEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index db86047..2f37943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.os.UserManager;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -66,6 +68,8 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
+        state.disabledByPolicy = mController.isTetheringAllowed();
+        checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
         if (arg instanceof Boolean) {
             state.value = (boolean) arg;
         } else {
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 724659c6..8328897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.os.UserManager;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -85,6 +87,8 @@
         // bug is fixed, this should be reverted to only hiding it on secure lock screens:
         // state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
         state.value = locationEnabled;
+        state.disabledByPolicy = mController.isUserLocationRestricted();
+        checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
         if (locationEnabled) {
             state.icon = mEnable;
             state.label = mContext.getString(R.string.quick_settings_location_label);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b78fd22..d1301cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,10 +19,12 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
+import android.app.UiModeManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -87,7 +89,10 @@
 
     public final static String RECENTS_PACKAGE = "com.android.systemui";
     public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
+    public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity";
 
+    //Used to store tv or non-tv activty for use in creating intents.
+    private final String mRecentsIntentActivityName;
     /**
      * An implementation of ITaskStackListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
@@ -210,6 +215,14 @@
         launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
         launchOpts.onlyLoadForCache = true;
         loader.loadTasks(mContext, plan, launchOpts);
+
+        //Manager used to determine if we are running on tv or not
+        UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
+        if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+            mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
+        } else {
+            mRecentsIntentActivityName = RECENTS_ACTIVITY;
+        }
     }
 
     public void onBootCompleted() {
@@ -906,10 +919,11 @@
         launchState.launchedViaDragGesture = mDraggingInRecents;
 
         Intent intent = new Intent();
-        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+        intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2882cec..aa006d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -81,6 +81,7 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
 /**
@@ -266,8 +267,9 @@
             ComponentName topActivity = topTask.topActivity;
 
             // Check if the front most activity is recents
-            if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
-                    topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
+            if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+                    (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
+                    topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
                 if (isHomeTopMost != null) {
                     isHomeTopMost.value = false;
                 }
@@ -356,6 +358,13 @@
     }
 
     /**
+     * Returns whether the given stack id is the pinned stack id.
+     */
+    public static boolean isPinnedStack(int stackId){
+        return stackId == PINNED_STACK_ID;
+    }
+
+    /**
      * Returns whether the given stack id is the docked stack id.
      */
     public static boolean isDockedStack(int stackId) {
@@ -968,4 +977,20 @@
     public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
         mWm.requestAppKeyboardShortcuts(receiver);
     }
+
+    public void focusPinnedStack() {
+        try {
+            mIam.setFocusedStack(PINNED_STACK_ID);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void focusHomeStack() {
+        try {
+            mIam.setFocusedStack(HOME_STACK_ID);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
new file mode 100644
index 0000000..6593169
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -0,0 +1,451 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowManager;
+import com.android.systemui.R;
+import com.android.systemui.recents.*;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.RecentsTvView;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.tv.pip.PipManager;
+
+import java.util.ArrayList;
+/**
+ * The main TV recents activity started by the RecentsImpl.
+ */
+public class RecentsTvActivity extends Activity implements OnPreDrawListener {
+    private final static String TAG = "RecentsTvActivity";
+    private final static boolean DEBUG = false;
+
+    public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+
+    private boolean mFinishedOnStartup;
+    private RecentsPackageMonitor mPackageMonitor;
+    private long mLastTabKeyEventTime;
+    private boolean mIgnoreAltTabRelease;
+
+    private RecentsTvView mRecentsView;
+    private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
+    private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+
+
+    /**
+     * A common Runnable to finish Recents by launching Home with an animation depending on the
+     * last activity launch state.  Generally we always launch home when we exit Recents rather than
+     * just finishing the activity since we don't know what is behind Recents in the task stack.
+     */
+    class FinishRecentsRunnable implements Runnable {
+        Intent mLaunchIntent;
+
+        /**
+         * Creates a finish runnable that starts the specified intent.
+         */
+        public FinishRecentsRunnable(Intent launchIntent) {
+            mLaunchIntent = launchIntent;
+        }
+
+        @Override
+        public void run() {
+            try {
+                RecentsActivityLaunchState launchState =
+                        Recents.getConfiguration().getLaunchState();
+                ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
+                        launchState.launchedFromSearchHome ?
+                                R.anim.recents_to_search_launcher_enter :
+                                R.anim.recents_to_launcher_enter,
+                        launchState.launchedFromSearchHome ?
+                                R.anim.recents_to_search_launcher_exit :
+                                R.anim.recents_to_launcher_exit);
+                startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+            } catch (Exception e) {
+                Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
+            }
+        }
+    }
+
+    private void updateRecentsTasks() {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+        if (plan == null) {
+            plan = loader.createLoadPlan(this);
+        }
+
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        if (!plan.hasTasks()) {
+            loader.preloadTasks(plan, -1, launchState.launchedFromHome);
+        }
+        TaskStack stack = plan.getTaskStack();
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = stack.getStackTaskCount();
+        loadOpts.numVisibleTaskThumbnails = stack.getStackTaskCount();
+        loader.loadTasks(this, plan, loadOpts);
+
+
+        mRecentsView.setTaskStack(stack);
+        if (mTaskStackViewAdapter == null) {
+            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+            mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
+        } else {
+            mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+        }
+
+        if (launchState.launchedToTaskId != -1) {
+            ArrayList<Task> tasks = stack.getStackTasks();
+            int taskCount = tasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                Task t = tasks.get(i);
+                if (t.key.id == launchState.launchedToTaskId) {
+                    t.isLaunchTarget = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchPreviousTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHome(true /* animateTaskViews */);
+        }
+        return false;
+    }
+
+    boolean dismissRecentsToFocusedTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchFocusedTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHome(true /* animateTaskViews */);
+            return true;
+        }
+        return false;
+    }
+
+    void dismissRecentsToHome(boolean animateTaskViews) {
+        DismissRecentsToHomeAnimationStarted dismissEvent =
+                new DismissRecentsToHomeAnimationStarted(animateTaskViews);
+        dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+        dismissEvent.addPostAnimationCallback(new Runnable() {
+            @Override
+            public void run() {
+                Recents.getSystemServices().sendCloseSystemWindows(
+                        BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+            }
+        });
+        EventBus.getDefault().send(dismissEvent);
+    }
+
+    boolean dismissRecentsToHomeIfVisible(boolean animated) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // Return to Home
+            dismissRecentsToHome(animated);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mFinishedOnStartup = false;
+
+        // In the case that the activity starts up before the Recents component has initialized
+        // (usually when debugging/pushing the SysUI apk), just finish this activity.
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp == null) {
+            mFinishedOnStartup = true;
+            finish();
+            return;
+        }
+
+        // Register this activity with the event bus
+        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
+        mPackageMonitor = new RecentsPackageMonitor();
+        mPackageMonitor.register(this);
+
+        // Set the Recents layout
+        setContentView(R.layout.recents_on_tv);
+
+        mRecentsView = (RecentsTvView) findViewById(R.id.recents_view);
+        mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+        getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
+        // Create the home intent runnable
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+        homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        // Update the recent tasks
+        updateRecentsTasks();
+
+        // If this is a new instance from a configuration change, then we have to manually trigger
+        // the enter animation state, or if recents was relaunched by AM, without going through
+        // the normal mechanisms
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+                !launchState.launchedFromAppWithThumbnail;
+        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+            EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+        }
+
+        // Notify that recents is now visible
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+    }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        super.onEnterAnimationComplete();
+        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        mIgnoreAltTabRelease = false;
+        // Notify that recents is now hidden
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+
+        // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+        // through SystemUI, we need to reset the config launch flags to ensure that we do not
+        // wait on the system to send a signal that was never queued.
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        launchState.launchedFromHome = false;
+        launchState.launchedFromSearchHome = false;
+        launchState.launchedFromAppWithThumbnail = false;
+        launchState.launchedToTaskId = -1;
+        launchState.launchedWithAltTab = false;
+        launchState.launchedHasConfigurationChanged = false;
+        launchState.launchedViaDragGesture = false;
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        // In the case that the activity finished on startup, just skip the unregistration below
+        if (mFinishedOnStartup) {
+            return;
+        }
+
+        // Unregister any broadcast receivers for the task loader
+        mPackageMonitor.unregister();
+
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        if (loader != null) {
+            loader.onTrimMemory(level);
+        }
+    }
+
+    @Override
+    public void onMultiWindowModeChanged(boolean multiWindowMode) {
+        super.onMultiWindowModeChanged(multiWindowMode);
+        if (!multiWindowMode) {
+            RecentsTaskLoader loader = Recents.getTaskLoader();
+            RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+            launchOpts.loadIcons = false;
+            launchOpts.loadThumbnails = false;
+            launchOpts.onlyLoadForCache = true;
+            RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+            loader.preloadTasks(loadPlan, -1, false);
+            loader.loadTasks(this, loadPlan, launchOpts);
+            EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP: {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                PipManager.getInstance().showPipMenu();
+                ssp.focusPinnedStack();
+                return true;
+            }
+            case KeyEvent.KEYCODE_DPAD_DOWN: {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                PipManager.getInstance().showPipOverlay(false);
+                ssp.focusHomeStack();
+                return true;
+            }
+            case KeyEvent.KEYCODE_DEL:
+            case KeyEvent.KEYCODE_FORWARD_DEL: {
+                EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+                return true;
+            }
+            default:
+                break;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public void onUserInteraction() {
+        EventBus.getDefault().send(new UserInteractionEvent());
+    }
+
+    @Override
+    public void onBackPressed() {
+        // Back behaves like the recents button so just trigger a toggle event
+        EventBus.getDefault().send(new ToggleRecentsEvent());
+    }
+
+    /**** EventBus events ****/
+
+    public final void onBusEvent(ToggleRecentsEvent event) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (launchState.launchedFromHome) {
+            dismissRecentsToHome(true /* animateTaskViews */);
+        } else {
+            dismissRecentsToLaunchTargetTaskOrHome();
+        }
+    }
+
+    public final void onBusEvent(HideRecentsEvent event) {
+        if (event.triggeredFromAltTab) {
+            // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+            if (!mIgnoreAltTabRelease) {
+                dismissRecentsToFocusedTaskOrHome();
+            }
+        } else if (event.triggeredFromHomeKey) {
+                dismissRecentsToHome(true /* animateTaskViews */);
+        } else {
+            // Do nothing
+        }
+    }
+
+    public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+        EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+        mRecentsView.invalidate();
+    }
+
+    public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        int launchToTaskId = launchState.launchedToTaskId;
+        if (launchToTaskId != -1 &&
+                (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.cancelWindowTransition(launchState.launchedToTaskId);
+            ssp.cancelThumbnailTransition(getTaskId());
+        }
+    }
+
+    public final void onBusEvent(DeleteTaskDataEvent event) {
+        // Remove any stored data from the loader
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        loader.deleteTaskData(event.task, false);
+
+        // Remove the task from activity manager
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ssp.removeTask(event.task.key.id);
+    }
+
+    public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.hasDockedTask()) {
+            mRecentsView.showEmptyView();
+        } else {
+            // Just go straight home (no animation necessary because there are no more task views)
+            dismissRecentsToHome(false /* animateTaskViews */);
+        }
+    }
+
+    public final void onBusEvent(LaunchTaskFailedEvent event) {
+        // Return to Home
+        dismissRecentsToHome(true /* animateTaskViews */);
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+        // We post to make sure that this information is delivered after this traversals is
+        // finished.
+        mRecentsView.post(new Runnable() {
+            @Override
+            public void run() {
+                Recents.getSystemServices().endProlongedAnimations();
+            }
+        });
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
new file mode 100644
index 0000000..8212c73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+import com.android.systemui.R;
+
+public class ViewFocusAnimator implements View.OnFocusChangeListener {
+    private final float mUnselectedScale;
+    private final float mSelectedScaleDelta;
+    private final float mUnselectedZ;
+    private final float mSelectedZDelta;
+    private final int mAnimDuration;
+    private final Interpolator mFocusInterpolator;
+
+    protected View mTargetView;
+    private float mFocusProgress;
+
+    ObjectAnimator mFocusAnimation;
+
+    public ViewFocusAnimator(View view) {
+        mTargetView = view;
+        final Resources res = view.getResources();
+
+        mTargetView.setOnFocusChangeListener(this);
+
+        TypedValue out = new TypedValue();
+        res.getValue(R.raw.unselected_scale, out, true);
+        mUnselectedScale = out.getFloat();
+        mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
+                mUnselectedScale;
+
+        mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
+        mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
+
+        mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
+
+        mFocusInterpolator = new AccelerateDecelerateInterpolator();
+
+        mFocusAnimation = ObjectAnimator.ofFloat(this, "focusProgress", 0.0f);
+        mFocusAnimation.setDuration(mAnimDuration);
+        mFocusAnimation.setInterpolator(mFocusInterpolator);
+
+        setFocusProgress(0.0f);
+
+        mFocusAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mTargetView.setHasTransientState(true);
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mTargetView.setHasTransientState(false);
+            }
+        });
+    }
+
+    public void setFocusProgress(float level) {
+        mFocusProgress = level;
+
+        float scale = mUnselectedScale + (level * mSelectedScaleDelta);
+        float z = mUnselectedZ + (level * mSelectedZDelta);
+
+        mTargetView.setScaleX(scale);
+        mTargetView.setScaleY(scale);
+        mTargetView.setZ(z);
+    }
+
+    public float getFocusProgress() {
+        return mFocusProgress;
+    }
+
+    public void animateFocus(boolean focused) {
+        if (mFocusAnimation.isStarted()) {
+            mFocusAnimation.cancel();
+        }
+
+        float target = focused ? 1.0f : 0.0f;
+
+        if (getFocusProgress() != target) {
+            mFocusAnimation.setFloatValues(getFocusProgress(), target);
+            mFocusAnimation.start();
+        }
+    }
+
+    public void setFocusImmediate(boolean focused) {
+        if (mFocusAnimation.isStarted()) {
+            mFocusAnimation.cancel();
+        }
+
+        float target = focused ? 1.0f : 0.0f;
+
+        setFocusProgress(target);
+    }
+
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (v != mTargetView) {
+            return;
+        }
+        changeSize(hasFocus);
+    }
+
+    protected void changeSize(boolean hasFocus) {
+        ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
+        int width = lp.width;
+        int height = lp.height;
+
+        if (width < 0 && height < 0) {
+            mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            height = mTargetView.getMeasuredHeight();
+        }
+
+        if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
+                mTargetView.getVisibility() == View.VISIBLE) {
+            animateFocus(hasFocus);
+        } else {
+            setFocusImmediate(hasFocus);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
new file mode 100644
index 0000000..c4d5b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
+/**
+ * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
+ */
+public class RecentsTvView extends FrameLayout {
+
+    private static final String TAG = "RecentsTvView";
+    private static final boolean DEBUG = false;
+
+    private TaskStack mStack;
+    private TaskStackHorizontalGridView mTaskStackHorizontalView;
+    private View mEmptyView;
+    private boolean mAwaitingFirstLayout = true;
+    private Rect mSystemInsets = new Rect();
+
+
+    public RecentsTvView(Context context) {
+        this(context, null);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        setWillNotDraw(false);
+
+        LayoutInflater inflater = LayoutInflater.from(context);
+        mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+        addView(mEmptyView);
+    }
+
+    public void setTaskStack(TaskStack stack) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        mStack = stack;
+
+        if (mTaskStackHorizontalView != null) {
+            mTaskStackHorizontalView.reset();
+            mTaskStackHorizontalView.setStack(stack);
+        } else {
+            mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
+            mTaskStackHorizontalView.setStack(stack);
+        }
+
+
+        if (stack.getStackTaskCount() > 0) {
+            hideEmptyView();
+        } else {
+            showEmptyView();
+        }
+
+        requestLayout();
+    }
+
+    public Task getNextTaskOrTopTask(Task taskToSearch) {
+        Task returnTask = null;
+        boolean found = false;
+        if (mTaskStackHorizontalView != null) {
+            TaskStack stack = mTaskStackHorizontalView.getStack();
+            ArrayList<Task> taskList = stack.getStackTasks();
+            // Iterate the stack views and try and find the focused task
+            for (int j = taskList.size() - 1; j >= 0; --j) {
+                Task task = taskList.get(j);
+                // Return the next task in the line.
+                if (found)
+                    return task;
+                // Remember the first possible task as the top task.
+                if (returnTask == null)
+                    returnTask = task;
+                if (task == taskToSearch)
+                    found = true;
+            }
+        }
+        return returnTask;
+    }
+
+    public boolean launchFocusedTask() {
+        if (mTaskStackHorizontalView != null) {
+            Task task = mTaskStackHorizontalView.getFocusedTask();
+            if (task != null) {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Launches the task that recents was launched from if possible */
+    public boolean launchPreviousTask() {
+        if (mTaskStackHorizontalView != null) {
+            TaskStack stack = mTaskStackHorizontalView.getStack();
+            Task task = stack.getLaunchTarget();
+            if (task != null) {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Launches a given task. */
+    public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
+        if (mTaskStackHorizontalView != null) {
+            // Iterate the stack views and try and find the given task.
+            List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int j = 0; j < taskViewCount; j++) {
+                TaskCardView tv = taskViews.get(j);
+                if (tv.getTask() == task) {
+                    SystemServicesProxy ssp = Recents.getSystemServices();
+                    ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Hides the task stack and shows the empty view.
+     */
+    public void showEmptyView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mEmptyView.bringToFront();
+    }
+
+    /**
+     * Shows the task stack and hides the empty view.
+     */
+    public void hideEmptyView() {
+        mEmptyView.setVisibility(View.INVISIBLE);
+    }
+
+    /**
+     * Returns the last known system insets.
+     */
+    public Rect getSystemInsets() {
+        return mSystemInsets;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+
+    /**
+     * This is called with the full size of the window since we are handling our own insets.
+     */
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
+            mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
+        }
+
+        // Layout the empty view
+        mEmptyView.layout(left, top, right, bottom);
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        mSystemInsets.set(insets.getSystemWindowInsets());
+        requestLayout();
+        return insets;
+    }
+
+    /**** EventBus Events ****/
+
+    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+        // If we are going home, cancel the previous task's window transition
+        EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+    }
+
+    public final void onBusEvent(TaskStackUpdatedEvent event) {
+        mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+        mStack.createAffiliatedGroupings(getContext());
+    }
+
+
+    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+        if (!event.visible) {
+            // Reset the view state
+            mAwaitingFirstLayout = true;
+        }
+    }
+
+
+    public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) {
+        if(mTaskStackHorizontalView != null) {
+            mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
new file mode 100644
index 0000000..b36a228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
+
+public class TaskCardView extends RelativeLayout {
+
+    private ImageView mThumbnailView;
+    private TextView mTitleTextView;
+    private TextView mContentTextView;
+    private ImageView mBadgeView;
+    private Task mTask;
+
+    private ViewFocusAnimator mViewFocusAnimator;
+
+    public TaskCardView(Context context) {
+        this(context, null);
+    }
+
+    public TaskCardView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mViewFocusAnimator = new ViewFocusAnimator(this);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+        mTitleTextView = (TextView) findViewById(R.id.card_title_text);
+        mContentTextView = (TextView) findViewById(R.id.card_content_text);
+        mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+    }
+
+    public void init(Task task) {
+        mTask = task;
+        mThumbnailView.setImageBitmap(task.thumbnail);
+        mTitleTextView.setText(task.title);
+        mContentTextView.setText(task.contentDescription);
+        mBadgeView.setImageDrawable(task.icon);
+    }
+
+    public Task getTask() {
+        return mTask;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
new file mode 100644
index 0000000..b505d65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv.views;
+
+
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.util.AttributeSet;
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
+import com.android.systemui.recents.views.TaskViewAnimation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Horizontal Grid View Implementation to show the Task Stack for TV.
+ */
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+
+    private TaskStack mStack;
+    private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
+    private Task mFocusedTask;
+
+
+    public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+    /**
+     * Resets this view for reuse.
+     */
+    public void reset() {
+        // Reset the focused task
+        resetFocusedTask(getFocusedTask());
+        requestLayout();
+    }
+
+    /**
+     * @param task - Task to reset
+     */
+    private void resetFocusedTask(Task task) {
+        if (task != null) {
+            TaskCardView tv = getChildViewForTask(task);
+            if (tv != null) {
+                tv.requestFocus();
+            }
+        }
+        mFocusedTask = null;
+    }
+
+    /**
+     * Sets the task stack.
+     * @param stack
+     */
+    public void setStack(TaskStack stack) {
+        //Set new stack
+        mStack = stack;
+        if (mStack != null) {
+            mStack.setCallbacks(this);
+        }
+        //Layout with new stack
+        requestLayout();
+    }
+
+    /**
+     * @return Returns the task stack.
+     */
+    public TaskStack getStack() {
+        return mStack;
+    }
+
+    /**
+     * @return - The focused task.
+     */
+    public Task getFocusedTask() {
+        return mFocusedTask;
+    }
+
+    /**
+     * @param task
+     * @return Child view for given task
+     */
+    public TaskCardView getChildViewForTask(Task task) {
+        List<TaskCardView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskCardView tv = taskViews.get(i);
+            if (tv.getTask() == task) {
+                return tv;
+            }
+        }
+        return null;
+    }
+
+    public List<TaskCardView> getTaskViews() {
+        return mTaskViews;
+    }
+
+    @Override
+    public void onStackTaskAdded(TaskStack stack, Task newTask){
+        getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
+    }
+
+    @Override
+    public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
+            Task newFrontMostTask, TaskViewAnimation animation) {
+        getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+        if (mFocusedTask == removedTask) {
+            resetFocusedTask(removedTask);
+        }
+        // If there are no remaining tasks, then just close recents
+        if (mStack.getStackTaskCount() == 0) {
+            boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
+            if (shouldFinishActivity) {
+                EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+            }
+        }
+    }
+
+    @Override
+    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation) {
+        //No history task on tv
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
new file mode 100644
index 0000000..0ee7b49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+import android.support.v7.widget.RecyclerView;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskStackHorizontalViewAdapter extends
+        RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
+
+    private static final String TAG = "TaskStackHorizontalViewAdapter";
+    private List<Task> mTaskList;
+
+    static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+        private TaskCardView mTaskCardView;
+        private Task mTask;
+        public ViewHolder(View v) {
+            super(v);
+            if(v instanceof TaskCardView) {
+                mTaskCardView = (TaskCardView) v;
+            }
+        }
+
+        public void init(Task task) {
+            mTaskCardView.init(task);
+            mTask = task;
+            mTaskCardView.setOnClickListener(this);
+        }
+
+        @Override
+        public void onClick(View v) {
+            try {
+                ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+                ((Activity)(v.getContext())).finish();
+            } catch (Exception e) {
+                Log.e(TAG, v.getContext()
+                        .getString(R.string.recents_launch_error_message, mTask.title), e);
+            }
+
+        }
+    }
+
+    public TaskStackHorizontalViewAdapter(List tasks) {
+        mTaskList = new ArrayList<>(tasks);
+    }
+
+    public void setNewStackTasks(List tasks) {
+        mTaskList.clear();
+        mTaskList.addAll(tasks);
+        notifyDataSetChanged();
+    }
+    @Override
+    public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+            int viewType) {
+        View view = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.recents_task_card_view, parent, false);
+        ViewHolder viewHolder = new ViewHolder(view);
+        return viewHolder;
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        holder.init(mTaskList.get(position));
+    }
+
+    @Override
+    public int getItemCount() {
+        return mTaskList.size();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 635e66d..3da8098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -460,16 +460,16 @@
         if (mDark == dark || mContractedChild == null) return;
         mDark = dark;
         dark = dark && !mShowingLegacyBackground;
-        if (mVisibleType == VISIBLE_TYPE_CONTRACTED) {
+        if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
             mContractedWrapper.setDark(dark, fade, delay);
         }
-        if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
+        if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
             mExpandedWrapper.setDark(dark, fade, delay);
         }
-        if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
+        if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
             mHeadsUpWrapper.setDark(dark, fade, delay);
         }
-        if (mSingleLineView != null && mVisibleType == VISIBLE_TYPE_SINGLELINE) {
+        if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
             mSingleLineView.setDark(dark, fade, delay);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index bed64a3..eb30120 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -30,6 +30,7 @@
 
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -62,8 +63,8 @@
     private SimpleArrayMap<String, Integer> mFacetPackageMap
             = new SimpleArrayMap<String, Integer>();
 
-    private List<Intent> mIntents = new ArrayList<Intent>();
-    private List<Intent> mLongPressIntents = new ArrayList<Intent>();
+    private List<Intent> mIntents;
+    private List<Intent> mLongPressIntents;
 
     private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
 
@@ -112,16 +113,19 @@
             throw new RuntimeException("car_facet array lengths do not match");
         }
 
+        mIntents = createEmptyIntentList(icons.length());
+        mLongPressIntents = createEmptyIntentList(icons.length());
+
         for (int i = 0; i < icons.length(); i++) {
             Drawable icon = icons.getDrawable(i);
             try {
-                mIntents.add(i,
+                mIntents.set(i,
                         Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
 
                 String longpressUri = longpressIntents.getString(i);
                 boolean hasLongpress = !longpressUri.isEmpty();
                 if (hasLongpress) {
-                    mLongPressIntents.add(i,
+                    mLongPressIntents.set(i,
                             Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
                 }
 
@@ -299,4 +303,8 @@
         setCurrentFacet(index);
         startActivity(mLongPressIntents.get(index));
     }
+
+    private List<Intent> createEmptyIntentList(int size) {
+        return Arrays.asList(new Intent[size]);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 97bf4b4..60c1911 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -35,6 +35,10 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
+        super.setDark(dark, fade, delay);
         if (fade) {
             mInvertHelper.fade(dark, delay);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index f43a5d0..85f789c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -95,6 +95,7 @@
 
     @Override
     public void notifyContentUpdated(StatusBarNotification notification) {
+        super.notifyContentUpdated(notification);
         // Reinspect the notification.
         resolveHeaderViews();
         updateInvertHelper();
@@ -150,6 +151,10 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
+        super.setDark(dark, fade, delay);
         if (fade) {
             mInvertHelper.fade(dark, delay);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 3475d13..9910dee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -172,6 +172,9 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
         super.setDark(dark, fade, delay);
         setPictureGrayscale(dark, fade, delay);
         setProgressBarDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a1cf07e..f50b976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -31,6 +31,7 @@
 public abstract class NotificationViewWrapper implements TransformableView {
 
     protected final View mView;
+    protected boolean mDark;
 
     public static NotificationViewWrapper wrap(Context ctx, View v) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -56,13 +57,17 @@
      * @param fade whether to animate the transition if the mode changes
      * @param delay if fading, the delay of the animation
      */
-    public abstract void setDark(boolean dark, boolean fade, long delay);
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mDark = dark;
+    }
 
     /**
      * Notifies this wrapper that the content of the view might have changed.
      * @param notification
      */
-    public void notifyContentUpdated(StatusBarNotification notification) {};
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        mDark = false;
+    };
 
     /**
      * Update the appearance of the expand button.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 8fa9c7e..e7e2ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -33,6 +33,7 @@
     Collection<CachedBluetoothDevice> getDevices();
     void connect(CachedBluetoothDevice device);
     void disconnect(CachedBluetoothDevice device);
+    boolean canConfigBluetooth();
 
     public interface Callback {
         void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index a04edf7..6439bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -39,6 +42,8 @@
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final LocalBluetoothManager mLocalBluetoothManager;
+    private final UserManager mUserManager;
+    private final int mCurrentUser;
 
     private boolean mEnabled;
     private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
@@ -54,6 +59,14 @@
             onBluetoothStateChanged(
                     mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
         }
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
+    }
+
+    @Override
+    public boolean canConfigBluetooth() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
+                UserHandle.of(mCurrentUser));
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 7ca91a5..b036936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,6 +22,7 @@
     boolean isHotspotEnabled();
     boolean isHotspotSupported();
     void setHotspotEnabled(boolean enabled);
+    boolean isTetheringAllowed();
 
     public interface Callback {
         void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5719f76..61d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 import com.android.settingslib.TetherUtil;
@@ -39,13 +42,17 @@
     private final Receiver mReceiver = new Receiver();
     private final ConnectivityManager mConnectivityManager;
     private final Context mContext;
+    private final UserManager mUserManager;
+    private final int mCurrentUser;
 
     private int mHotspotState;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
-        mConnectivityManager = (ConnectivityManager)context.getSystemService(
+        mConnectivityManager = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,6 +102,12 @@
         return TetherUtil.isTetheringSupported(mContext);
     }
 
+    @Override
+    public boolean isTetheringAllowed() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
+                UserHandle.of(mCurrentUser));
+    }
+
     static final class OnStartTetheringCallback extends
             ConnectivityManager.OnStartTetheringCallback {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..401943e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,6 +21,7 @@
     boolean setLocationEnabled(boolean enabled);
     void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
     void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
+    boolean isUserLocationRestricted();
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 7517f97..436a40d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,6 +52,7 @@
 
     private AppOpsManager mAppOpsManager;
     private StatusBarManager mStatusBarManager;
+    private final int mCurrentUser;
 
     private boolean mAreActiveLocationRequests;
 
@@ -73,6 +74,7 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mStatusBarManager
                 = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
 
         // Examine the current location state and initialize the status view.
         updateActiveLocationRequests();
@@ -103,10 +105,6 @@
      * @return true if attempt to change setting was successful.
      */
     public boolean setLocationEnabled(boolean enabled) {
-        int currentUserId = ActivityManager.getCurrentUser();
-        if (isUserLocationRestricted(currentUserId)) {
-            return false;
-        }
         final ContentResolver cr = mContext.getContentResolver();
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
@@ -115,7 +113,7 @@
         // QuickSettings always runs as the owner, so specifically set the settings
         // for the current foreground user.
         return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
     }
 
     /**
@@ -133,11 +131,10 @@
     /**
      * Returns true if the current user is restricted from using location.
      */
-    private boolean isUserLocationRestricted(int userId) {
+    public boolean isUserLocationRestricted() {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        return um.hasUserRestriction(
-                UserManager.DISALLOW_SHARE_LOCATION,
-                new UserHandle(userId));
+        return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+                UserHandle.of(mCurrentUser));
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e4ded67..f5869b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -622,7 +622,7 @@
 
     private void checkIfAddUserDisallowed(UserRecord record) {
         EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
-                UserManager.DISALLOW_ADD_USER, UserHandle.myUserId());
+                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
         if (admin != null) {
             record.isDisabledByAdmin = true;
             record.enforcedAdmin = admin;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index b7a41e2..964688b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,12 +17,15 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_JACK_FLAGS := --multi-dex native
+
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 
 LOCAL_AAPT_FLAGS := --auto-add-overlay \
-    --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview
+    --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
+    --extra-packages android.support.v17.leanback
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-Iaidl-files-under, src) \
@@ -35,6 +38,7 @@
     frameworks/support/v14/preference/res \
     frameworks/support/v7/appcompat/res \
     frameworks/support/v7/recyclerview/res \
+    frameworks/support/v17/leanback/res \
     frameworks/base/packages/SystemUI/res \
     frameworks/base/packages/Keyguard/res
 
@@ -48,7 +52,8 @@
     android-support-v7-recyclerview \
     android-support-v7-preference \
     android-support-v7-appcompat \
-    android-support-v14-preference
+    android-support-v14-preference \
+    android-support-v17-leanback
 
 # sign this with platform cert, so this test is allowed to inject key events into
 # UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76fbebf..b5982c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12970,6 +12970,9 @@
 
         final StringBuilder sb = new StringBuilder(1024);
         appendDropBoxProcessHeaders(process, processName, sb);
+        sb.append("Foreground: ")
+                .append(process.isInterestingToUserLocked() ? "Yes" : "No")
+                .append("\n");
         if (activity != null) {
             sb.append("Activity: ").append(activity.shortComponentName).append("\n");
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e0880ad..e6fa837 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -74,6 +74,12 @@
     /** Content limits relative to the DisplayContent this sits in. */
     private Rect mBounds = new Rect();
 
+    /** Screen content area excluding IM windows, etc. */
+    private final Rect mContentBounds = new Rect();
+
+    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+    private final Rect mAdjustedBounds = new Rect();
+
     /** Whether mBounds is fullscreen */
     private boolean mFullscreen = true;
 
@@ -164,6 +170,85 @@
         return mTmpRect.equals(bounds);
     }
 
+    void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+        if (mFullscreen) {
+            return;
+        }
+        // Update bounds of containing tasks.
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.get(taskNdx);
+            if (task.isTwoFingerScrollMode()) {
+                // If we're scrolling we don't care about your bounds or configs,
+                // they should be null as if we were in fullscreen.
+                task.resizeLocked(null, null, false /* forced */);
+                task.getBounds(mTmpRect2);
+                task.scrollLocked(mTmpRect2);
+            } else if (task.isResizeable()) {
+                task.getBounds(mTmpRect2);
+                mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+                task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
+            }
+        }
+    }
+
+    void adjustForIME(final WindowState imeWin) {
+        final int dockedSide = getDockSide();
+        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+        final Rect adjustedBounds = mAdjustedBounds;
+        if (imeWin == null || !dockedTopOrBottom) {
+            // If mContentBounds is already empty, it means we're not applying
+            // any adjustments, so nothing to do; otherwise clear any adjustments.
+            if (!mContentBounds.isEmpty()) {
+                mContentBounds.setEmpty();
+                adjustedBounds.set(mBounds);
+                alignTasksToAdjustedBounds(adjustedBounds);
+            }
+            return;
+        }
+
+        final Rect displayContentRect = mTmpRect;
+        final Rect contentBounds = mTmpRect2;
+
+        // Calculate the content bounds excluding the area occupied by IME
+        mDisplayContent.getContentRect(displayContentRect);
+        contentBounds.set(displayContentRect);
+        int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+        imeTop += imeWin.getGivenContentInsetsLw().top;
+        if (contentBounds.bottom > imeTop) {
+            contentBounds.bottom = imeTop;
+        }
+
+        // If content bounds not changing, nothing to do.
+        if (mContentBounds.equals(contentBounds)) {
+            return;
+        }
+
+        // Content bounds changed, need to apply adjustments depending on dock sides.
+        mContentBounds.set(contentBounds);
+        adjustedBounds.set(mBounds);
+        final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+        if (dockedSide == DOCKED_TOP) {
+            // If this stack is docked on top, we make it smaller so the bottom stack is not
+            // occluded by IME. We shift its bottom up by the height of the IME (capped by
+            // the display content rect). Note that we don't change the task bounds.
+            adjustedBounds.bottom = Math.max(
+                    adjustedBounds.bottom - yOffset, displayContentRect.top);
+        } else {
+            // If this stack is docked on bottom, we shift it up so that it's not occluded by
+            // IME. We try to move it up by the height of the IME window (although the best
+            // we could do is to make the top stack fully collapsed).
+            final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
+            adjustedBounds.top = Math.max(
+                    adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+            adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+
+            // We also move the member tasks together, taking care not to resize them.
+            // Resizing might cause relaunch, and IME window may not come back after that.
+            alignTasksToAdjustedBounds(adjustedBounds);
+        }
+    }
+
     private boolean setBounds(Rect bounds) {
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
@@ -193,6 +278,16 @@
 
         mBounds.set(bounds);
         mRotation = rotation;
+
+        // Clear the adjusted content bounds as they're no longer valid.
+        // If IME is still visible, these will be re-applied.
+        // Note that we don't clear mContentBounds here, so that we know the last IME
+        // adjust we applied.
+        // If user starts dragging the dock divider while IME is visible, the new bounds
+        // we received are based on the actual screen location of the divider. It already
+        // accounted for the IME window, so we don't want to adjust again.
+        mAdjustedBounds.set(mBounds);
+
         return true;
     }
 
@@ -217,9 +312,14 @@
 
     public void getBounds(Rect out) {
         if (useCurrentBounds()) {
-            // No need to adjust the output bounds if fullscreen or the docked stack is visible
+            // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
+            // no need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
-            out.set(mBounds);
+            if (!mContentBounds.isEmpty()) {
+                out.set(mAdjustedBounds);
+            } else {
+                out.set(mBounds);
+            }
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2b88af4..e0e44dc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -161,6 +161,7 @@
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -8075,8 +8076,29 @@
                 }
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     synchronized (mWindowMap) {
-                        getDefaultDisplayContentLocked().getDockedDividerController()
-                                .reevaluateVisibility(false);
+                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+
+                        displayContent.getDockedDividerController().reevaluateVisibility(false);
+
+                        final WindowState imeWin = mInputMethodWindow;
+                        final TaskStack focusedStack =
+                                mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+                        if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
+                                && focusedStack.getDockSide() == DOCKED_BOTTOM){
+                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
+                            for (int i = stacks.size() - 1; i >= 0; --i) {
+                                final TaskStack stack = stacks.get(i);
+                                if (stack.isVisibleLocked()) {
+                                    stack.adjustForIME(imeWin);
+                                }
+                            }
+                        } else {
+                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
+                            for (int i = stacks.size() - 1; i >= 0; --i) {
+                                final TaskStack stack = stacks.get(i);
+                                stack.adjustForIME(null);
+                            }
+                        }
                     }
                 }
                 break;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 236ae68e..1b0660d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -195,7 +195,7 @@
 
     private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
 
-    protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
+    private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
             = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
 
     private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
@@ -1703,8 +1703,8 @@
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
      */
-    private void setExpirationAlarmCheckLocked(Context context, int userHandle) {
-        final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false);
+    private void setExpirationAlarmCheckLocked(Context context, int userHandle, boolean parent) {
+        final long expiration = getPasswordExpirationLocked(null, userHandle, parent);
         final long now = System.currentTimeMillis();
         final long timeToExpire = expiration - now;
         final long alarmTime;
@@ -1726,11 +1726,12 @@
 
         long token = mInjector.binderClearCallingIdentity();
         try {
+            int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
             AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
             PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
                     new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
-                    UserHandle.of(userHandle));
+                    UserHandle.of(affectedUserHandle));
             am.cancel(pi);
             if (alarmTime != 0) {
                 am.set(AlarmManager.RTC, alarmTime, pi);
@@ -2489,7 +2490,6 @@
         synchronized (this) {
             final long now = System.currentTimeMillis();
 
-            // Return the strictest policy across all participating admins.
             List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
                     userHandle, /* parent */ false);
             final int N = admins.size();
@@ -2503,7 +2503,7 @@
                             DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
                 }
             }
-            setExpirationAlarmCheckLocked(mContext, userHandle);
+            setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
         }
     }
 
@@ -2976,8 +2976,7 @@
             saveSettingsLocked(userHandle);
 
             // in case this is the first one, set the alarm on the appropriate user.
-            int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
-            setExpirationAlarmCheckLocked(mContext, affectedUserHandle);
+            setExpirationAlarmCheckLocked(mContext, userHandle, parent);
         }
     }
 
@@ -4324,7 +4323,7 @@
                 policy.mFailedPasswordAttempts = 0;
                 saveSettingsLocked(userHandle);
                 updatePasswordExpirationsLocked(userHandle);
-                setExpirationAlarmCheckLocked(mContext, userHandle);
+                setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
 
                 // Send a broadcast to each profile using this password as its primary unlock.
                 sendAdminCommandForLockscreenPoliciesLocked(
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b4bca3e..6c2fcd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -26,7 +26,10 @@
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /** Test {@link UserManager} functionality. */
@@ -196,6 +199,17 @@
         assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
     }
 
+    public void testGetSerialNumbersOfUsers() {
+        UserInfo user1 = createUser("User 1", 0);
+        UserInfo user2 = createUser("User 2", 0);
+        long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
+        String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
+        assertTrue(errMsg + user1.serialNumber,
+                ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
+        assertTrue(errMsg + user2.serialNumber,
+                ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+    }
+
     public void testMaxUsers() {
         int N = UserManager.getMaxSupportedUsers();
         int count = mUserManager.getUsers().size();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81031da..bfdac7e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@
     static final int MSG_PAROLE_END_TIMEOUT = 7;
     static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
     static final int MSG_PAROLE_STATE_CHANGED = 9;
+    static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
 
     private final Object mLock = new Object();
     Handler mHandler;
@@ -145,7 +146,7 @@
     private long mLastAppIdleParoledTime;
 
     long mScreenOnTime;
-    long mScreenOnSystemTimeSnapshot;
+    long mLastScreenOnEventRealtime;
 
     @GuardedBy("mLock")
     private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +189,8 @@
 
         synchronized (mLock) {
             cleanUpRemovedUsersLocked();
+            mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+            mScreenOnTime = readScreenOnTimeLocked();
         }
 
         mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,10 +217,6 @@
                     Context.DISPLAY_SERVICE);
             mPowerManager = getContext().getSystemService(PowerManager.class);
 
-            mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
-            synchronized (mLock) {
-                mScreenOnTime = readScreenOnTimeLocked();
-            }
             mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
             synchronized (mLock) {
                 updateDisplayLocked();
@@ -281,6 +280,11 @@
     }
 
     @Override
+    public void onStatsReloaded() {
+        postOneTimeCheckIdleStates();
+    }
+
+    @Override
     public long getAppIdleRollingWindowDurationMillis() {
         return mAppIdleWallclockThresholdMillis * 2;
     }
@@ -359,6 +363,14 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
     }
 
+    /**
+     * We send a different message to check idle states once, otherwise we would end up
+     * scheduling a series of repeating checkIdleStates each time we fired off one.
+     */
+    void postOneTimeCheckIdleStates() {
+        mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+    }
+
     /** Check all running users' or specified user's apps to see if they enter an idle state. */
     void checkIdleStates(int checkUserId) {
         if (!mAppIdleEnabled) {
@@ -385,7 +397,7 @@
                             userId);
             synchronized (mLock) {
                 final long timeNow = checkAndGetTimeLocked();
-                final long screenOnTime = getScreenOnTimeLocked(timeNow);
+                final long screenOnTime = getScreenOnTimeLocked();
                 UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
                         timeNow);
                 final int packageCount = packages.size();
@@ -401,8 +413,6 @@
                 }
             }
         }
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
-                mCheckIdleIntervalMillis);
     }
 
     /** Check if it's been a while since last parole and let idle apps do some work */
@@ -443,21 +453,21 @@
         if (screenOn == mScreenOn) return;
 
         mScreenOn = screenOn;
-        long now = System.currentTimeMillis();
+        long now = SystemClock.elapsedRealtime();
         if (mScreenOn) {
-            mScreenOnSystemTimeSnapshot = now;
+            mLastScreenOnEventRealtime = now;
         } else {
-            mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+            mScreenOnTime += now - mLastScreenOnEventRealtime;
             writeScreenOnTimeLocked(mScreenOnTime);
         }
     }
 
-    private long getScreenOnTimeLocked(long now) {
+    long getScreenOnTimeLocked() {
+        long screenOnTime = mScreenOnTime;
         if (mScreenOn) {
-            return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
-        } else {
-            return mScreenOnTime;
+            screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
         }
+        return screenOnTime;
     }
 
     private File getScreenOnTimeFile() {
@@ -527,7 +537,7 @@
         if (service == null) {
             service = new UserUsageStatsService(getContext(), userId,
                     new File(mUsageStatsDir, Integer.toString(userId)), this);
-            service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+            service.init(currentTimeMillis, getScreenOnTimeLocked());
             mUserState.put(userId, service);
         }
         return service;
@@ -540,25 +550,18 @@
         final long actualSystemTime = System.currentTimeMillis();
         final long actualRealtime = SystemClock.elapsedRealtime();
         final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
-        boolean resetBeginIdleTime = false;
-        if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+        final long diffSystemTime = actualSystemTime - expectedSystemTime;
+        if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
             // The time has changed.
-
-            // Check if it's severe enough a change to reset screenOnTime
-            if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
-                mScreenOnSystemTimeSnapshot = actualSystemTime;
-                mScreenOnTime = 0;
-                resetBeginIdleTime = true;
-            }
+            Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
             final int userCount = mUserState.size();
             for (int i = 0; i < userCount; i++) {
                 final UserUsageStatsService service = mUserState.valueAt(i);
-                service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
-                        resetBeginIdleTime);
+                service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+                        false);
             }
             mRealTimeSnapshot = actualRealtime;
             mSystemTimeSnapshot = actualSystemTime;
-            postCheckIdleStates(UserHandle.USER_ALL);
         }
         return actualSystemTime;
     }
@@ -587,7 +590,7 @@
     void reportEvent(UsageEvents.Event event, int userId) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long screenOnTime = getScreenOnTimeLocked(timeNow);
+            final long screenOnTime = getScreenOnTimeLocked();
             convertToSystemTimeLocked(event);
 
             final UserUsageStatsService service =
@@ -603,7 +606,6 @@
                     || event.mEventType == Event.SYSTEM_INTERACTION
                     || event.mEventType == Event.USER_INTERACTION)) {
                 if (previouslyIdle) {
-                    //Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                             /* idle = */ 0, event.mPackage));
                     notifyBatteryStats(event.mPackage, userId, false);
@@ -643,7 +645,7 @@
     void forceIdleState(String packageName, int userId, boolean idle) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long screenOnTime = getScreenOnTimeLocked(timeNow);
+            final long screenOnTime = getScreenOnTimeLocked();
             final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
 
             final UserUsageStatsService service =
@@ -657,7 +659,6 @@
                     timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
             // Inform listeners if necessary
             if (previouslyIdle != idle) {
-                // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                         /* idle = */ idle ? 1 : 0, packageName));
                 if (!idle) {
@@ -796,7 +797,7 @@
                 timeNow = checkAndGetTimeLocked();
             }
             userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            screenOnTime = getScreenOnTimeLocked(timeNow);
+            screenOnTime = getScreenOnTimeLocked();
         }
         return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
                 userService, timeNow, screenOnTime);
@@ -865,7 +866,7 @@
         synchronized (mLock) {
             timeNow = checkAndGetTimeLocked();
             userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            screenOnTime = getScreenOnTimeLocked(timeNow);
+            screenOnTime = getScreenOnTimeLocked();
         }
 
         List<ApplicationInfo> apps;
@@ -987,7 +988,7 @@
      */
     void dump(String[] args, PrintWriter pw) {
         synchronized (mLock) {
-            final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+            final long screenOnTime = getScreenOnTimeLocked();
             IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
             ArraySet<String> argSet = new ArraySet<>();
             argSet.addAll(Arrays.asList(args));
@@ -1008,7 +1009,11 @@
                 }
                 idpw.decreaseIndent();
             }
-            pw.println("Screen On Timebase:" + mScreenOnTime);
+            pw.print("Screen On Timebase: ");
+            pw.print(screenOnTime);
+            pw.print(" (");
+            TimeUtils.formatDuration(screenOnTime, pw);
+            pw.println(")");
 
             pw.println();
             pw.println("Settings:");
@@ -1042,8 +1047,8 @@
             pw.println();
             pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
             pw.println();
-            pw.print("mScreenOnSystemTimeSnapshot=");
-            TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+            pw.print("mLastScreenOnEventRealtime=");
+            TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
             pw.println();
         }
     }
@@ -1078,6 +1083,14 @@
 
                 case MSG_CHECK_IDLE_STATES:
                     checkIdleStates(msg.arg1);
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                            MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+                            mCheckIdleIntervalMillis);
+                    break;
+
+                case MSG_ONE_TIME_CHECK_IDLE_STATES:
+                    mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+                    checkIdleStates(UserHandle.USER_ALL);
                     break;
 
                 case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1138,7 +1151,7 @@
         @Override
         public void onChange(boolean selfChange) {
             updateSettings();
-            postCheckIdleStates(UserHandle.USER_ALL);
+            postOneTimeCheckIdleStates();
         }
 
         void updateSettings() {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index aa2cf77..f2045d3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -73,6 +73,7 @@
 
     interface StatsUpdatedListener {
         void onStatsUpdated();
+        void onStatsReloaded();
         long getAppIdleRollingWindowDurationMillis();
     }
 
@@ -523,6 +524,9 @@
 
         mStatsChanged = false;
         updateRolloverDeadline();
+
+        // Tell the listener that the stats reloaded, which may have changed idle states.
+        mListener.onStatsReloaded();
     }
 
     private void updateRolloverDeadline() {
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ff3d29f..ec9e462 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -43,7 +43,8 @@
     void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
     void subscribe(int sessionId, in SubscribeData subscribeData,
             in SubscribeSettings subscribeSettings);
-    void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength);
+    void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength,
+            int messageId);
     void stopSession(int sessionId);
     void destroySession(int sessionId);
 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
index 773f83b..50c34d9 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
@@ -32,7 +32,7 @@
     void onMatch(int peerId, in byte[] serviceSpecificInfo,
             int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
 
-    void onMessageSendSuccess();
-    void onMessageSendFail(int reason);
+    void onMessageSendSuccess(int messageId);
+    void onMessageSendFail(int messageId, int reason);
     void onMessageReceived(int peerId, in byte[] message, int messageLength);
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 877f993..cb82268 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -319,13 +319,14 @@
     /**
      * {@hide}
      */
-    public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength) {
+    public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+            int messageId) {
         try {
             if (VDBG) {
                 Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
-                        + ", messageLength=" + messageLength);
+                        + ", messageLength=" + messageLength + ", messageId=" + messageId);
             }
-            mService.sendMessage(sessionId, peerId, message, messageLength);
+            mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
         } catch (RemoteException e) {
             Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
         }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c6b384e..d0a9410 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -103,8 +103,11 @@
      * @param message The message to be transmitted.
      * @param messageLength The number of bytes from the {@code message} to be
      *            transmitted.
+     * @param messageId An arbitrary integer used by the caller to identify the
+     *            message. The same integer ID will be returned in the callbacks
+     *            indicated message send success or failure.
      */
-    public void sendMessage(int peerId, byte[] message, int messageLength) {
-        mManager.sendMessage(mSessionId, peerId, message, messageLength);
+    public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+        mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index c9d08c7..d5e59f0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -210,10 +210,10 @@
                                 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
                         break;
                     case LISTEN_MESSAGE_SEND_SUCCESS:
-                        WifiNanSessionListener.this.onMessageSendSuccess();
+                        WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1);
                         break;
                     case LISTEN_MESSAGE_SEND_FAIL:
-                        WifiNanSessionListener.this.onMessageSendFail(msg.arg1);
+                        WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2);
                         break;
                     case LISTEN_MESSAGE_RECEIVED:
                         WifiNanSessionListener.this.onMessageReceived(msg.arg2,
@@ -306,7 +306,7 @@
      * {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
      * never both.
      */
-    public void onMessageSendSuccess() {
+    public void onMessageSendSuccess(int messageId) {
         if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
     }
 
@@ -325,7 +325,7 @@
      * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
      *            codes.
      */
-    public void onMessageSendFail(int reason) {
+    public void onMessageSendFail(int messageId, int reason) {
         if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
     }
 
@@ -401,19 +401,21 @@
         }
 
         @Override
-        public void onMessageSendSuccess() {
+        public void onMessageSendSuccess(int messageId) {
             if (VDBG) Log.v(TAG, "onMessageSendSuccess");
 
             Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+            msg.arg1 = messageId;
             mHandler.sendMessage(msg);
         }
 
         @Override
-        public void onMessageSendFail(int reason) {
+        public void onMessageSendFail(int messageId, int reason) {
             if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
 
             Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
-            msg.arg1 = reason;
+            msg.arg1 = messageId;
+            msg.arg2 = reason;
             mHandler.sendMessage(msg);
         }