Merge "resolve merge conflicts of 3629c67 to master"
diff --git a/api/current.txt b/api/current.txt
index d062d9b..0a8965f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30307,6 +30307,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -30315,6 +30317,7 @@
     method public android.print.PageRange[] getPages();
     method public android.print.PrinterId getPrinterId();
     method public int getState();
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index 7a69f76..2b5c33d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -32907,6 +32907,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -32915,6 +32917,7 @@
     method public android.print.PageRange[] getPages();
     method public android.print.PrinterId getPrinterId();
     method public int getState();
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
diff --git a/api/test-current.txt b/api/test-current.txt
index d4631c3..4de2c61 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -30382,6 +30382,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -30392,6 +30394,7 @@
     method public float getProgress();
     method public int getState();
     method public java.lang.CharSequence getStatus(android.content.pm.PackageManager);
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 74f48c6..02c8f0c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3037,6 +3037,18 @@
             "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
 
     /**
+     * Broadcast sent to the system user when the 'device locked' state changes for any user.
+     * Carries an extra {@link #EXTRA_USER_HANDLE} that specifies the ID of the user for which
+     * the device was locked or unlocked.
+     *
+     * This is only sent to registered receivers.
+     *
+     * @hide
+     */
+    public static final String ACTION_DEVICE_LOCKED_CHANGED =
+            "android.intent.action.DEVICE_LOCKED_CHANGED";
+
+    /**
      * Sent when the user taps on the clock widget in the system's "quick settings" area.
      */
     public static final String ACTION_QUICK_CLOCK =
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index f134943..3d094f7 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -586,8 +586,6 @@
      *
      * @param key The option key.
      * @return Whether the option is present.
-     *
-     * @hide
      */
     public boolean hasAdvancedOption(String key) {
         return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
@@ -598,8 +596,6 @@
      *
      * @param key The option key.
      * @return The option value.
-     *
-     * @hide
      */
     public String getAdvancedStringOption(String key) {
         if (mAdvancedOptions != null) {
@@ -613,8 +609,6 @@
      *
      * @param key The option key.
      * @return The option value.
-     *
-     * @hide
      */
     public int getAdvancedIntOption(String key) {
         if (mAdvancedOptions != null) {
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 2baa0b4..16f2d7d 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -26,7 +26,7 @@
 //TODO: Improve Javadoc
 /**
  * Represents an event that is sent out by the system at various times during a drag and drop
- * operation. It is a complex data structure that contains several important pieces of data about
+ * operation. It is a data structure that contains several important pieces of data about
  * the operation and the underlying data.
  * <p>
  *  View objects that receive a DragEvent call {@link #getAction()}, which returns
@@ -161,8 +161,8 @@
      *  event when they are added or becoming visible.
      * </p>
      * <p>
-     *  A View only receives further drag events if it returns {@code true} in response to
-     *  ACTION_DRAG_STARTED.
+     *  A View only receives further drag events for the drag operation if it returns {@code true}
+     *  in response to ACTION_DRAG_STARTED.
      * </p>
      * @see #ACTION_DRAG_ENDED
      * @see #getX()
@@ -172,8 +172,9 @@
 
     /**
      * Action constant returned by {@link #getAction()}: Sent to a View after
-     * {@link #ACTION_DRAG_ENTERED} if the drag shadow is still within the View object's bounding
-     * box. The {@link #getX()} and {@link #getY()} methods supply
+     * {@link #ACTION_DRAG_ENTERED} while the drag shadow is still within the View object's bounding
+     * box, but not within a descendant view that can accept the data. The {@link #getX()} and
+     * {@link #getY()} methods supply
      * the X and Y position of of the drag point within the View object's bounding box.
      * <p>
      * A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
@@ -355,9 +356,10 @@
     /**
      * Returns the {@link android.content.ClipData} object sent to the system as part of the call
      * to
-     * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+     * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+     * startDragAndDrop()}.
      * This method only returns valid data if the event action is {@link #ACTION_DROP}.
-     * @return The ClipData sent to the system by startDrag().
+     * @return The ClipData sent to the system by startDragAndDrop().
      */
     public ClipData getClipData() {
         return mClipData;
@@ -366,12 +368,14 @@
     /**
      * Returns the {@link android.content.ClipDescription} object contained in the
      * {@link android.content.ClipData} object sent to the system as part of the call to
-     * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+     * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+     * startDragAndDrop()}.
      * The drag handler or listener for a View can use the metadata in this object to decide if the
      * View can accept the dragged View object's data.
      * <p>
      * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
-     * @return The ClipDescription that was part of the ClipData sent to the system by startDrag().
+     * @return The ClipDescription that was part of the ClipData sent to the system by
+     *     startDragAndDrop().
      */
     public ClipDescription getClipDescription() {
         return mClipDescription;
@@ -384,7 +388,8 @@
 
     /**
      * Returns the local state object sent to the system as part of the call to
-     * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+     * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+     * startDragAndDrop()}.
      * The object is intended to provide local information about the drag and drop operation. For
      * example, it can indicate whether the drag and drop operation is a copy or a move.
      * <p>
@@ -394,7 +399,7 @@
      * <p>
      *  This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
      * </p>
-     * @return The local state object sent to the system by startDrag().
+     * @return The local state object sent to the system by startDragAndDrop().
      */
     public Object getLocalState() {
         return mLocalState;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index deb3f90..bdf93e4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20832,6 +20832,9 @@
      *  {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or
      *  {@code false} if it didn't.
      * </p>
+     * <p>
+     *  For all other events, the return value is ignored.
+     * </p>
      */
     public boolean onDragEvent(DragEvent event) {
         return false;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 44f6fac..c125b32 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -92,9 +92,6 @@
     /** @hide */
     public static final int AUTOCLICK_DELAY_DEFAULT = 600;
 
-    /** @hide */
-    public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20;
-
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
@@ -103,8 +100,6 @@
 
     private IAccessibilityManager mService;
 
-    private EventDispatchThread mEventDispatchThread;
-
     final int mUserId;
 
     final Handler mHandler;
@@ -303,32 +298,44 @@
      * their descendants.
      */
     public void sendAccessibilityEvent(AccessibilityEvent event) {
-        if (!isEnabled()) {
-            Looper myLooper = Looper.myLooper();
-            if (myLooper == Looper.getMainLooper()) {
-                throw new IllegalStateException(
-                        "Accessibility off. Did you forget to check that?");
-            } else {
-                // If we're not running on the thread with the main looper, it's possible for
-                // the state of accessibility to change between checking isEnabled and
-                // calling this method. So just log the error rather than throwing the
-                // exception.
-                Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
+        final IAccessibilityManager service;
+        final int userId;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
                 return;
             }
-        }
-        event.setEventTime(SystemClock.uptimeMillis());
-
-        getEventDispatchThread().scheduleEvent(event);
-    }
-
-    private EventDispatchThread getEventDispatchThread() {
-        synchronized (mLock) {
-            if (mEventDispatchThread == null) {
-                mEventDispatchThread = new EventDispatchThread(mService, mUserId);
-                mEventDispatchThread.start();
+            if (!mIsEnabled) {
+                Looper myLooper = Looper.myLooper();
+                if (myLooper == Looper.getMainLooper()) {
+                    throw new IllegalStateException(
+                            "Accessibility off. Did you forget to check that?");
+                } else {
+                    // If we're not running on the thread with the main looper, it's possible for
+                    // the state of accessibility to change between checking isEnabled and
+                    // calling this method. So just log the error rather than throwing the
+                    // exception.
+                    Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
+                    return;
+                }
             }
-            return mEventDispatchThread;
+            userId = mUserId;
+        }
+        try {
+            event.setEventTime(SystemClock.uptimeMillis());
+            // it is possible that this manager is in the same process as the service but
+            // client using it is called through Binder from another process. Example: MMS
+            // app adds a SMS notification and the NotificationManagerService calls this method
+            long identityToken = Binder.clearCallingIdentity();
+            service.sendAccessibilityEvent(event, userId);
+            Binder.restoreCallingIdentity(identityToken);
+            if (DEBUG) {
+                Log.i(LOG_TAG, event + " sent");
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error during sending " + event + " ", re);
+        } finally {
+            event.recycle();
         }
     }
 
@@ -713,99 +720,4 @@
             }
         }
     }
-
-    private static class EventDispatchThread extends Thread {
-        // Second lock used to keep UI thread performant. Never try to grab mLock when holding
-        // this one, or the UI thread will block in send AccessibilityEvent.
-        private final Object mEventQueueLock = new Object();
-
-        // Two lists to hold events. The app thread fills one while we empty the other.
-        private final ArrayList<AccessibilityEvent> mEventLists0 =
-                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
-        private final ArrayList<AccessibilityEvent> mEventLists1 =
-                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
-
-        private boolean mPingPongListToggle;
-
-        private final IAccessibilityManager mService;
-
-        private final int mUserId;
-
-        EventDispatchThread(IAccessibilityManager service, int userId) {
-            mService = service;
-            mUserId = userId;
-        }
-
-        @Override
-        public void run() {
-            while (true) {
-                ArrayList<AccessibilityEvent> listBeingDrained;
-                synchronized (mEventQueueLock) {
-                    ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked();
-                    if (listBeingFilled.isEmpty()) {
-                        try {
-                            mEventQueueLock.wait();
-                        } catch (InterruptedException e) {
-                            // Treat as a notify
-                        }
-                    }
-                    // Swap buffers
-                    mPingPongListToggle = !mPingPongListToggle;
-                    listBeingDrained = listBeingFilled;
-                }
-                dispatchEvents(listBeingDrained);
-            }
-        }
-
-        public void scheduleEvent(AccessibilityEvent event) {
-            synchronized (mEventQueueLock) {
-                getListBeingFilledLocked().add(event);
-                mEventQueueLock.notifyAll();
-            }
-        }
-
-        private ArrayList<AccessibilityEvent> getListBeingFilledLocked() {
-            return (mPingPongListToggle) ? mEventLists0 : mEventLists1;
-        }
-
-        private void dispatchEvents(ArrayList<AccessibilityEvent> events) {
-            int eventListCapacityLowerBound = events.size();
-            while (events.size() > 0) {
-                // We don't want to consume extra memory if an app sends a lot of events in a
-                // one-off event. Cap the list length at double the max events per call.
-                // We'll end up with extra GC for apps that send huge numbers of events, but
-                // sending that many events will lead to bad performance in any case.
-                if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)
-                        && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) {
-                    events.trimToSize();
-                    eventListCapacityLowerBound = events.size();
-                }
-                // We only expect this loop to run once, as the app shouldn't be sending
-                // huge numbers of events.
-                // The clear in the called method will remove the sent events
-                dispatchOneBatchOfEvents(events.subList(0,
-                        Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL)));
-            }
-        }
-
-        private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) {
-            if (events.isEmpty()) {
-                return;
-            }
-            long identityToken = Binder.clearCallingIdentity();
-            try {
-                mService.sendAccessibilityEvents(new ParceledListSlice<>(events),
-                        mUserId);
-            } catch (RemoteException re) {
-                Log.e(LOG_TAG, "Error sending multiple events");
-            }
-            Binder.restoreCallingIdentity(identityToken);
-            if (DEBUG) {
-                Log.i(LOG_TAG, events.size() + " events sent");
-            }
-            for (int i = events.size() - 1; i >= 0; i--) {
-                events.remove(i).recycle();
-            }
-        }
-    }
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index aa9cb39..71e77c4 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -21,7 +21,6 @@
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
-import android.content.pm.ParceledListSlice;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -30,7 +29,7 @@
 
 /**
  * Interface implemented by the AccessibilityManagerService called by
- * the AccessibilityMasngers.
+ * the AccessibilityManagers.
  *
  * @hide
  */
@@ -40,8 +39,6 @@
 
     void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
 
-    void sendAccessibilityEvents(in ParceledListSlice events, int userId);
-
     List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
     List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a08c63e..d4bef17 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -496,6 +496,8 @@
 
     <protected-broadcast android:name="com.android.server.retaildemo.ACTION_RESET_DEMO" />
 
+    <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
diff --git a/core/tests/coretests/src/android/print/WorkflowTest.java b/core/tests/coretests/src/android/print/WorkflowTest.java
index 35cfe22..62d8b97 100644
--- a/core/tests/coretests/src/android/print/WorkflowTest.java
+++ b/core/tests/coretests/src/android/print/WorkflowTest.java
@@ -27,27 +27,33 @@
 import android.print.mockservice.StubbablePrinterDiscoverySession;
 import android.print.pdf.PrintedPdfDocument;
 import android.support.test.filters.LargeTest;
+import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
 import android.util.Log;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 /**
  * Tests for the basic printing workflows
  */
+@RunWith(Parameterized.class)
 public class WorkflowTest extends BasePrintTest {
     private static final String LOG_TAG = WorkflowTest.class.getSimpleName();
 
@@ -55,6 +61,17 @@
     private static float sTransitionAnimationScaleBefore;
     private static float sAnimatiorDurationScaleBefore;
 
+    private PrintAttributes.MediaSize mFirst;
+    private boolean mSelectPrinter;
+    private PrintAttributes.MediaSize mSecond;
+
+    public WorkflowTest(PrintAttributes.MediaSize first, boolean selectPrinter,
+            PrintAttributes.MediaSize second) {
+        mFirst = first;
+        mSelectPrinter = selectPrinter;
+        mSecond = second;
+    }
+
     interface InterruptableConsumer<T> {
         void accept(T t) throws InterruptedException;
     }
@@ -155,16 +172,23 @@
         PrinterCapabilitiesInfo.Builder builder =
                 new PrinterCapabilitiesInfo.Builder(printerId);
 
-        builder.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
-                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                        PrintAttributes.COLOR_MODE_COLOR)
-                .addMediaSize(mediaSize, true)
-                .addResolution(new PrintAttributes.Resolution("300x300", "300x300", 300, 300),
-                        true);
+        PrinterInfo printerInfo;
+        if (mediaSize != null) {
+            builder.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .addMediaSize(mediaSize, true)
+                    .addResolution(new PrintAttributes.Resolution("300x300", "300x300", 300, 300),
+                            true);
 
-        printers.add(new PrinterInfo.Builder(printerId, name,
-                PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build());
+            printerInfo = new PrinterInfo.Builder(printerId, name,
+                    PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+        } else {
+            printerInfo = (new PrinterInfo.Builder(printerId, name,
+                    PrinterInfo.STATUS_IDLE)).build();
+        }
 
+        printers.add(printerInfo);
         session.addPrinters(printers);
     }
 
@@ -193,28 +217,42 @@
      *
      * @param sessionRef Where to store the reference to the session once started
      */
-    private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef) {
+    private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef,
+            ArrayList<String> trackedPrinters, PrintAttributes.MediaSize mediaSize) {
         MockPrintService.setCallbacks(createMockPrintServiceCallbacks(
                 inv -> createMockPrinterDiscoverySessionCallbacks(inv2 -> {
                             synchronized (sessionRef) {
                                 sessionRef[0] = ((PrinterDiscoverySessionCallbacks) inv2.getMock())
                                         .getSession();
 
-                                addPrinter(sessionRef[0], "1st printer",
-                                        PrintAttributes.MediaSize.ISO_A0);
+                                addPrinter(sessionRef[0], "1st printer", mediaSize);
 
                                 sessionRef.notifyAll();
                             }
                             return null;
                         },
-                        null, null, null, null, null, inv2 -> {
+                        null, null, inv2 -> {
+                            synchronized (trackedPrinters) {
+                                trackedPrinters
+                                        .add(((PrinterId) inv2.getArguments()[0]).getLocalId());
+                                trackedPrinters.notifyAll();
+                            }
+                            return null;
+                        }, null, inv2 -> {
+                            synchronized (trackedPrinters) {
+                                trackedPrinters
+                                        .remove(((PrinterId) inv2.getArguments()[0]).getLocalId());
+                                trackedPrinters.notifyAll();
+                            }
+                            return null;
+                        }, inv2 -> {
                             synchronized (sessionRef) {
                                 sessionRef[0] = null;
                                 sessionRef.notifyAll();
                             }
                             return null;
                         }
-        ), null, null));
+                ), null, null));
     }
 
     /**
@@ -271,13 +309,37 @@
         }, null);
     }
 
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        ArrayList<Object[]> tests = new ArrayList<>();
+
+        for (PrintAttributes.MediaSize first : new PrintAttributes.MediaSize[]{
+                PrintAttributes.MediaSize.ISO_A0, null}) {
+            for (Boolean selectPrinter : new Boolean[]{true, false}) {
+                for (PrintAttributes.MediaSize second : new PrintAttributes.MediaSize[]{
+                        PrintAttributes.MediaSize.ISO_A1, null}) {
+                    // If we do not use the second printer, no need to try various options
+                    if (!selectPrinter && second == null) {
+                        continue;
+                    }
+                    tests.add(new Object[]{first, selectPrinter, second});
+                }
+            }
+        }
+
+        return tests;
+    }
+
     @Test
     @LargeTest
     public void addAndSelectPrinter() throws Exception {
         final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
         final PrintAttributes printAttributes[] = new PrintAttributes[1];
+        ArrayList<String> trackedPrinters = new ArrayList<>();
 
-        setMockPrintServiceCallbacks(session);
+        Log.i(LOG_TAG, "Running " + mFirst + " " + mSelectPrinter + " " + mSecond);
+
+        setMockPrintServiceCallbacks(session, trackedPrinters, mFirst);
         print(printAttributes);
 
         // We are now in the PrintActivity
@@ -288,11 +350,23 @@
 
         setPrinter("1st printer");
 
-        Log.i(LOG_TAG, "Waiting for print attributes to change");
-        synchronized (printAttributes) {
-            waitWithTimeout(
-                    () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
-                            PrintAttributes.MediaSize.ISO_A0), printAttributes::wait);
+        Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+        synchronized (trackedPrinters) {
+            waitWithTimeout(() -> !trackedPrinters.contains("1st printer"), trackedPrinters::wait);
+        }
+
+        if (mFirst != null) {
+            Log.i(LOG_TAG, "Waiting for print attributes to change");
+            synchronized (printAttributes) {
+                waitWithTimeout(
+                        () -> printAttributes[0] == null ||
+                                !printAttributes[0].getMediaSize().equals(
+                                        mFirst), printAttributes::wait);
+            }
+        } else {
+            Log.i(LOG_TAG, "Waiting for error message");
+            assertNotNull(getUiDevice().wait(Until.findObject(
+                    By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
         }
 
         setPrinter("All printers\u2026");
@@ -302,67 +376,7 @@
 
         // We are now in the AddPrinterActivity
         AddPrintersActivity.addObserver(
-                () -> addPrinter(session[0], "2nd printer", PrintAttributes.MediaSize.ISO_A1));
-
-        // This executes the observer registered above
-        clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
-                        .resourceId("com.android.printspooler:id/title"));
-
-        getUiDevice().pressBack();
-        AddPrintersActivity.clearObservers();
-
-        // We are now in the SelectPrinterActivity
-        clickOnText("2nd printer");
-
-        // We are now in the PrintActivity
-        Log.i(LOG_TAG, "Waiting for print attributes to change");
-        synchronized (printAttributes) {
-            waitWithTimeout(
-                    () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
-                            PrintAttributes.MediaSize.ISO_A1), printAttributes::wait);
-        }
-
-        getUiDevice().pressBack();
-
-        // We are back in the test activity
-        Log.i(LOG_TAG, "Waiting for session to end");
-        synchronized (session) {
-            waitWithTimeout(() -> session[0] != null, session::wait);
-        }
-    }
-
-    @Test
-    @LargeTest
-    public void abortSelectingPrinter() throws Exception {
-        final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
-        final PrintAttributes printAttributes[] = new PrintAttributes[1];
-
-        setMockPrintServiceCallbacks(session);
-        print(printAttributes);
-
-        // We are now in the PrintActivity
-        Log.i(LOG_TAG, "Waiting for session");
-        synchronized (session) {
-            waitWithTimeout(() -> session[0] == null, session::wait);
-        }
-
-        setPrinter("1st printer");
-
-        Log.i(LOG_TAG, "Waiting for print attributes to change");
-        synchronized (printAttributes) {
-            waitWithTimeout(
-                    () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
-                            PrintAttributes.MediaSize.ISO_A0), printAttributes::wait);
-        }
-
-        setPrinter("All printers\u2026");
-
-        // We are now in the SelectPrinterActivity
-        clickOnText("Add printer");
-
-        // We are now in the AddPrinterActivity
-        AddPrintersActivity.addObserver(
-                () -> addPrinter(session[0], "2nd printer", PrintAttributes.MediaSize.ISO_A1));
+                () -> addPrinter(session[0], "2nd printer", mSecond));
 
         // This executes the observer registered above
         clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
@@ -371,14 +385,63 @@
         getUiDevice().pressBack();
         AddPrintersActivity.clearObservers();
 
-        // Do not select a new printer, just press back
-        getUiDevice().pressBack();
+        if (mSelectPrinter) {
+            // We are now in the SelectPrinterActivity
+            clickOnText("2nd printer");
+        } else {
+            getUiDevice().pressBack();
+        }
 
         // We are now in the PrintActivity
-        // The media size should not change
-        Log.i(LOG_TAG, "Make sure print attributes did not change");
-        Thread.sleep(100);
-        assertEquals(PrintAttributes.MediaSize.ISO_A0, printAttributes[0].getMediaSize());
+        if (mSelectPrinter) {
+            if (mSecond != null) {
+                Log.i(LOG_TAG, "Waiting for print attributes to change");
+                synchronized (printAttributes) {
+                    waitWithTimeout(
+                            () -> printAttributes[0] == null ||
+                                    !printAttributes[0].getMediaSize().equals(
+                                            mSecond), printAttributes::wait);
+                }
+            } else {
+                Log.i(LOG_TAG, "Waiting for error message");
+                assertNotNull(getUiDevice().wait(Until.findObject(
+                        By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+            }
+
+            Log.i(LOG_TAG, "Waiting for 1st printer to be not tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> trackedPrinters.contains("1st printer"),
+                        trackedPrinters::wait);
+            }
+
+            Log.i(LOG_TAG, "Waiting for 2nd printer to be tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> !trackedPrinters.contains("2nd printer"),
+                        trackedPrinters::wait);
+            }
+        } else {
+            Thread.sleep(100);
+
+            if (mFirst != null) {
+                Log.i(LOG_TAG, "Waiting for print attributes to change");
+                synchronized (printAttributes) {
+                    waitWithTimeout(
+                            () -> printAttributes[0] == null ||
+                                    !printAttributes[0].getMediaSize().equals(
+                                            mFirst), printAttributes::wait);
+                }
+            } else {
+                Log.i(LOG_TAG, "Waiting for error message");
+                assertNotNull(getUiDevice().wait(Until.findObject(
+                        By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+            }
+
+            Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> !trackedPrinters.contains("1st printer"),
+                        trackedPrinters::wait);
+            }
+        }
 
         getUiDevice().pressBack();
 
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index d6e07a56..9280818 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -157,19 +157,22 @@
 </p>
 <p>
     Your application tells the system to start a drag by calling the
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()}
     method. This tells the system to start sending drag events. The method also sends the data that
     you are dragging.
 </p>
 <p>
     You can call
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()}
     for any attached View in the current layout. The system only uses the View object to get access
     to global settings in your layout.
 </p>
 <p>
     Once your application calls
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()},
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()},
     the rest of the process uses events that the system sends to the View objects in your current
     layout.
 </p>
@@ -183,11 +186,13 @@
     </dt>
     <dd>
         In response to the user's gesture to begin a drag, your application calls
-        {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
-        to tell the system to start a drag. The arguments
-        {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
-        provide the data to be dragged, metadata for this data, and a callback for drawing the
-        drag shadow.
+        {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+        startDragAndDrop()}
+        to tell the system to start a drag. The
+        {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+        startDragAndDrop()}
+        arguments provide the data to be dragged, metadata for this data, and a callback for drawing
+        the drag shadow.
         <p>
             The system first responds by calling back to your application to get a drag shadow. It
             then displays the drag shadow on the device.
@@ -199,12 +204,13 @@
             including a possible drop event, a drag event listener must return <code>true</code>.
             This registers the listener with the system. Only registered listeners continue to
             receive drag events. At this point, listeners can also change the appearance of their
-            View object to show that the listener can accept a drop event.
+            View object to show that the listener can accept the dragged data.
         </p>
         <p>
             If the drag event listener returns <code>false</code>, then it will not receive drag
-            events for the current operation until the system sends a drag event with action type
-            {@link android.view.DragEvent#ACTION_DRAG_ENDED}. By sending <code>false</code>, the
+            events for the current operation, including the drag event with action type
+            {@link android.view.DragEvent#ACTION_DRAG_ENDED} that will conclude the
+            operation. By sending <code>false</code>, the
             listener tells the system that it is not interested in the drag operation and
             does not want to accept the dragged data.
         </p>
@@ -230,7 +236,8 @@
         object's listener a drag event with action type
         {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was
         passed to the system in the call to
-        {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+        {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+        startDragAndDrop()}
         that started the operation. The listener is expected to return boolean <code>true</code> to
         the system if code for accepting the drop succeeds.
         <p>
@@ -297,7 +304,8 @@
 <p>
     The {@link android.view.DragEvent} object also contains the data that your application provided
     to the system in the call to
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()}.
     Some of the data is valid only for certain action types. The data that is valid for each action
     type is summarized in <a href="#table2">table 2</a>. It is also described in detail with
     the event for which it is valid in the section
@@ -316,8 +324,9 @@
         <td>
             A View object's drag event listener receives this event action type just after the
             application calls
-{@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and
-            gets a drag shadow.
+            {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+            startDragAndDrop()}
+            and gets a drag shadow.
             <p>
                 If the listener wants to continue receiving drag events for this operation, it must
                 return boolean <code>true</code> to the system.
@@ -345,8 +354,7 @@
         <td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td>
         <td>
             A View object's drag event listener receives this event action type after it receives a
-            {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one
-            {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved
+            {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and after the user has moved
             the drag shadow outside the bounding box of the View or into a descendant view that can
             accept the data.
         </td>
@@ -355,7 +363,8 @@
         <td>{@link android.view.DragEvent#ACTION_DROP}</td>
         <td>
             A View object's drag event listener receives this event action type when the user
-            releases the drag shadow over the View object. This action type is only sent to a View
+            releases the drag shadow over the View object and not over its descendant view that can
+            accept the drag data. This action type is only sent to a View
             object's listener if the listener returned boolean <code>true</code> in response to the
             {@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event. This action type is not
             sent if the user releases the drag shadow on a View whose listener is not registered,
@@ -472,9 +481,11 @@
     The image is called a drag shadow. You create it with methods you declare for a
     {@link android.view.View.DragShadowBuilder} object, and then pass it to the system when you
     start a drag using
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()}.
     As part of its response to
-    {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()},
+    {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+    startDragAndDrop()},
     the system invokes the callback methods you've defined in
     {@link android.view.View.DragShadowBuilder} to obtain a drag shadow.
 </p>
@@ -516,7 +527,8 @@
     </dt>
     <dd>
         The system calls this method immediately after you call
-{@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. Use it
+        {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+        startDragAndDrop()}. Use it
         to send to the system the dimensions and touch point of the drag shadow. The method has two
         arguments:
         <dl>
@@ -616,10 +628,10 @@
 
     // Starts the drag
 
-            v.startDrag(dragData,  // the data to be dragged
-                        myShadow,  // the drag shadow builder
-                        null,      // no need to use local data
-                        0          // flags (not currently used, set to 0)
+            v.startDragAndDrop(dragData,  // the data to be dragged
+                               myShadow,  // the drag shadow builder
+                               null,      // no need to use local data
+                               0          // flags (not currently used, set to 0)
             );
 
     }
@@ -722,8 +734,7 @@
 <p>
     Note that for an {@link android.view.DragEvent#ACTION_DRAG_STARTED} event, these
     the following {@link android.view.DragEvent} methods are not valid:
-    {@link android.view.DragEvent#getClipData()}, {@link android.view.DragEvent#getX()},
-    {@link android.view.DragEvent#getY()}, and {@link android.view.DragEvent#getResult()}.
+    {@link android.view.DragEvent#getClipData()} and {@link android.view.DragEvent#getResult()}.
 </p>
 <h3 id="HandleDuring">Handling events during the drag</h3>
 <p>
@@ -751,7 +762,9 @@
         {@link android.view.DragEvent#ACTION_DRAG_LOCATION}: Once the listener receives an
         {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and before it receives an
         A{@link android.view.DragEvent#ACTION_DRAG_EXITED} event, it receives a new
-        {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event every time the touch point moves.
+        {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event immediately after the
+        {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and then every time the touch
+        point moves.
         The {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} methods
         return the X and Y coordinates of the touch point.
     </li>
@@ -769,9 +782,9 @@
 </p>
 <ul>
     <li>
-        In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or
-        {@link android.view.DragEvent#ACTION_DRAG_LOCATION}, the listener can change the appearance
-        of the View to indicate that it is about to receive a drop.
+        In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, the listener can change
+        the appearance
+        of the View to indicate that it is ready to receive a drop.
     </li>
     <li>
         An event with the action type {@link android.view.DragEvent#ACTION_DRAG_LOCATION} contains
@@ -784,14 +797,14 @@
     <li>
         In response to {@link android.view.DragEvent#ACTION_DRAG_EXITED}, the listener should reset
         any appearance changes it applied in response to
-        {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or
-        {@link android.view.DragEvent#ACTION_DRAG_LOCATION}. This indicates to the user that
+        {@link android.view.DragEvent#ACTION_DRAG_ENTERED}. This indicates to the user that
         the View is no longer an imminent drop target.
     </li>
 </ul>
 <h3 id="HandleDrop">Responding to a drop</h3>
 <p>
-    When the user releases the drag shadow on a View in the application, and that View previously
+    When the user releases the drag shadow on a View in the application, but not on its descendant
+    view that can accept the data, and that View previously
     reported that it could accept the content being dragged, the system dispatches a drag event
     to that View with the action type {@link android.view.DragEvent#ACTION_DROP}. The listener
     should do the following:
@@ -800,8 +813,8 @@
     <li>
         Call {@link android.view.DragEvent#getClipData()} to get the
         {@link android.content.ClipData} object that was originally supplied in the call
-        to
-{@link android.view.View#startDrag(ClipData, View.DragShadowBuilder, Object, int) startDrag()}
+        to {@link android.view.View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)
+        startDragAndDrop()}
         and store it. If the drag and drop operation does not represent data movement,
         this may not be necessary.
     </li>
@@ -856,9 +869,6 @@
         including any case in which the system did not send out a
         {@link android.view.DragEvent#ACTION_DROP} event.
     </li>
-    <li>
-        The listener should return boolean <code>true</code> to the system.
-    </li>
 </ol>
 <p>
 </p>
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index a9b7062..401012f 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -352,7 +352,7 @@
                                     effectCallback,
                                     &lpJniStorage->mCallbackData,
                                     (audio_session_t) sessionId,
-                                    0);
+                                    AUDIO_IO_HANDLE_NONE);
     if (lpAudioEffect == 0) {
         ALOGE("Error creating AudioEffect");
         goto setup_failure;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index b3cfea5..23c6615 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -46,7 +46,6 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.print.IPrintDocumentAdapter;
 import android.print.PageRange;
@@ -760,8 +759,11 @@
                 mPrintJob.setPrinterId(printerInfo.getId());
                 mPrintJob.setPrinterName(printerInfo.getName());
 
-                if (printerInfo.getCapabilities() != null) {
+                if (canPrint(printerInfo)) {
                     updatePrintAttributesFromCapabilities(printerInfo.getCapabilities());
+                    onPrinterAvailable(printerInfo);
+                } else {
+                    onPrinterUnavailable(printerInfo);
                 }
 
                 mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
@@ -2050,7 +2052,7 @@
     }
 
     public void onPrinterUnavailable(PrinterInfo printer) {
-        if (mCurrentPrinter.getId().equals(printer.getId())) {
+        if (mCurrentPrinter == null || mCurrentPrinter.getId().equals(printer.getId())) {
             setState(STATE_PRINTER_UNAVAILABLE);
             mPrintedDocument.cancel(false);
             ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
@@ -2309,8 +2311,7 @@
         public int getPrinterIndex(PrinterId printerId) {
             for (int i = 0; i < getCount(); i++) {
                 PrinterHolder printerHolder = (PrinterHolder) getItem(i);
-                if (printerHolder != null && !printerHolder.removed
-                        && printerHolder.printer.getId().equals(printerId)) {
+                if (printerHolder != null && printerHolder.printer.getId().equals(printerId)) {
                     return i;
                 }
             }
@@ -2539,7 +2540,11 @@
                 if (updatedPrinter != null) {
                     printerHolder.printer = updatedPrinter;
                     printerHolder.removed = false;
-                    onPrinterAvailable(printerHolder.printer);
+                    if (canPrint(printerHolder.printer)) {
+                        onPrinterAvailable(printerHolder.printer);
+                    } else {
+                        onPrinterUnavailable(printerHolder.printer);
+                    }
                     newPrinterHolders.add(printerHolder);
                 } else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
                     printerHolder.removed = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a7132e5..7a1ea47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -161,7 +161,7 @@
             "com.android.systemui.statusbar.banner_action_cancel";
     private static final String BANNER_ACTION_SETUP =
             "com.android.systemui.statusbar.banner_action_setup";
-    private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
+    private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
             = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
 
     protected CommandQueue mCommandQueue;
@@ -217,14 +217,14 @@
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     // public mode, private notifications, etc
-    private boolean mLockscreenPublicMode = false;
+    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
 
     private UserManager mUserManager;
     private int mDensity;
 
-    private KeyguardManager mKeyguardManager;
+    protected KeyguardManager mKeyguardManager;
     private LockPatternUtils mLockPatternUtils;
 
     // UI-specific methods
@@ -465,11 +465,11 @@
             row.setUserExpanded(true);
 
             if (!mAllowLockscreenRemoteInput) {
-                if (isLockscreenPublicMode()) {
+                final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+                if (isLockscreenPublicMode(userId)) {
                     onLockedRemoteInput(row, view);
                     return true;
                 }
-                final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
                 if (mUserManager.getUserInfo(userId).isManagedProfile()
                         && mKeyguardManager.isDeviceLocked(userId)) {
                     onLockedWorkRemoteInput(userId, row, view);
@@ -560,7 +560,7 @@
 
                     );
                 }
-            } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
+            } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
                 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
                 if (intentSender != null) {
@@ -577,7 +577,6 @@
                         /* ignore */
                     }
                 }
-                onWorkChallengeUnlocked();
             }
         }
     };
@@ -585,12 +584,18 @@
     private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
             if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
                     isCurrentProfile(getSendingUserId())) {
                 mUsersAllowingPrivateNotifications.clear();
                 updateLockscreenNotificationSetting();
                 updateNotifications();
+            } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+                if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+                    onWorkChallengeChanged();
+                }
             }
         }
     };
@@ -815,7 +820,7 @@
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         IntentFilter internalFilter = new IntentFilter();
-        internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+        internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         internalFilter.addAction(BANNER_ACTION_CANCEL);
         internalFilter.addAction(BANNER_ACTION_SETUP);
         mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
@@ -823,6 +828,7 @@
         IntentFilter allUsersFilter = new IntentFilter();
         allUsersFilter.addAction(
                 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
         mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
                 null, null);
         updateCurrentProfilesCache();
@@ -1126,9 +1132,10 @@
             @Override
             public void onClick(View v) {
                 // If the user has security enabled, show challenge if the setting is changed.
-                if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
-                        (mState == StatusBarState.KEYGUARD
-                        || mState == StatusBarState.SHADE_LOCKED)) {
+                if (guts.hasImportanceChanged()
+                            && isLockscreenPublicMode(sbn.getUser().getIdentifier())
+                            && (mState == StatusBarState.KEYGUARD
+                                    || mState == StatusBarState.SHADE_LOCKED)) {
                     OnDismissAction dismissAction = new OnDismissAction() {
                         @Override
                         public boolean onDismiss() {
@@ -1430,15 +1437,15 @@
     /**
      * Save the current "public" (locked and secure) state of the lockscreen.
      */
-    public void setLockscreenPublicMode(boolean publicMode) {
-        mLockscreenPublicMode = publicMode;
+    public void setLockscreenPublicMode(boolean publicMode, int userId) {
+        mLockscreenPublicMode.put(userId, publicMode);
     }
 
-    public boolean isLockscreenPublicMode() {
-        return mLockscreenPublicMode;
+    public boolean isLockscreenPublicMode(int userId) {
+        return mLockscreenPublicMode.get(userId, false);
     }
 
-    protected void onWorkChallengeUnlocked() {}
+    protected void onWorkChallengeChanged() {}
 
     /**
      * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
@@ -1496,8 +1503,9 @@
      * If so, notifications should be hidden.
      */
     @Override  // NotificationData.Environment
-    public boolean shouldHideNotifications(int userid) {
-        return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+    public boolean shouldHideNotifications(int userId) {
+        return isLockscreenPublicMode(mCurrentUserId) && !userAllowsNotificationsInPublic(userId)
+                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
     }
 
     /**
@@ -1506,7 +1514,7 @@
      */
     @Override // NotificationDate.Environment
     public boolean shouldHideNotifications(String key) {
-        return isLockscreenPublicMode()
+        return isLockscreenPublicMode(mCurrentUserId)
                 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
     }
 
@@ -1514,8 +1522,8 @@
      * Returns true if we're on a secure lockscreen.
      */
     @Override  // NotificationData.Environment
-    public boolean onSecureLockScreen() {
-        return isLockscreenPublicMode();
+    public boolean isSecurelyLocked(int userId) {
+        return isLockscreenPublicMode(userId);
     }
 
     public void onNotificationClear(StatusBarNotification notification) {
@@ -2076,8 +2084,7 @@
         if (newIntent == null) {
             return false;
         }
-        final Intent callBackIntent = new Intent(
-                WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+        final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
         callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
         callBackIntent.setPackage(mContext.getPackageName());
@@ -2276,14 +2283,16 @@
                 entry.row.setOnKeyguard(false);
                 entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
             }
+            int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
             boolean childWithVisibleSummary = childNotification
                     && mGroupManager.getGroupSummary(entry.notification).getVisibility()
                     == View.VISIBLE;
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
-            if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
-                    (onKeyguard && !childWithVisibleSummary
+            if (suppressedSummary
+                    || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
+                    || (onKeyguard && !childWithVisibleSummary
                             && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
                 entry.row.setVisibility(View.GONE);
                 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index b6e54af..bae16f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -380,7 +380,7 @@
             return true;
         }
 
-        if (mEnvironment.onSecureLockScreen() &&
+        if (mEnvironment.isSecurelyLocked(sbn.getUserId()) &&
                 (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
                         || mEnvironment.shouldHideNotifications(sbn.getUserId())
                         || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
@@ -463,7 +463,7 @@
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface Environment {
-        public boolean onSecureLockScreen();
+        public boolean isSecurelyLocked(int userId);
         public boolean shouldHideNotifications(int userid);
         public boolean shouldHideNotifications(String key);
         public boolean isDeviceProvisioned();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 706abdc..34b8371 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -96,9 +96,10 @@
         }
 
         final int activeUserId = ActivityManager.getCurrentUser();
-        final boolean allowDismissKeyguard =
-                !UserManager.isSplitSystemUser()
-                && activeUserId == keyguardUserId;
+        final boolean isSystemUser =
+                UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
+        final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
+
         // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
         // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
         if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 8ee014c..a442fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -37,6 +37,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -1765,18 +1766,21 @@
         for (int i=0; i<N; i++) {
             Entry ent = activeNotifications.get(i);
             int vis = ent.notification.getNotification().visibility;
+            int userId = ent.notification.getUserId();
 
             // Display public version of the notification if we need to redact.
-            final boolean hideSensitive =
-                    !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+            boolean deviceSensitive = (isLockscreenPublicMode(mCurrentUserId)
+                    && !userAllowsPrivateNotificationsInPublic(mCurrentUserId));
+            boolean userSensitive = deviceSensitive || (isLockscreenPublicMode(userId)
+                    && !userAllowsPrivateNotificationsInPublic(userId));
             boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
             boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
-            boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
-            boolean showingPublic = sensitive && isLockscreenPublicMode();
+            boolean sensitive = (sensitiveNote && userSensitive) || sensitivePackage;
+            boolean showingPublic = sensitive && isLockscreenPublicMode(userId);
             if (showingPublic) {
                 updatePublicContentView(ent, ent.notification);
             }
-            ent.row.setSensitive(sensitive, hideSensitive);
+            ent.row.setSensitive(sensitive, deviceSensitive);
             if (ent.autoRedacted && ent.legacy) {
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
                 // for legacy auto redacted notifications.
@@ -4333,17 +4337,23 @@
     }
 
     private void updatePublicMode() {
-        boolean isPublic = false;
-        if (mStatusBarKeyguardViewManager.isShowing()) {
-            for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
-                UserInfo userInfo = mCurrentProfiles.valueAt(i);
-                if (mStatusBarKeyguardViewManager.isSecure(userInfo.id)) {
-                    isPublic = true;
-                    break;
+        final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
+        final boolean devicePublic = showingKeyguard
+                && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
+
+        // Look for public mode users. Users are considered public in either case of:
+        //   - device keyguard is shown in secure mode;
+        //   - profile is locked with a work challenge.
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            final int userId = mCurrentProfiles.valueAt(i).id;
+            boolean isProfilePublic = devicePublic;
+            if (!devicePublic && userId != mCurrentUserId) {
+                if (mStatusBarKeyguardViewManager.isSecure(userId)) {
+                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
                 }
             }
+            setLockscreenPublicMode(isProfilePublic, userId);
         }
-        setLockscreenPublicMode(isPublic);
     }
 
     protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -4400,7 +4410,8 @@
     public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
         if (mStackScroller == null) return;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
-        mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
+        boolean publicMode = isAnyProfilePublicMode();
+        mStackScroller.setHideSensitive(publicMode, goingToFullShade);
         mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
         mStackScroller.setExpandingEnabled(!onKeyguard);
         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
@@ -4650,6 +4661,7 @@
      * @param expandView The view to expand after going to the shade.
      */
     public void goToLockedShade(View expandView) {
+        int userId = mCurrentUserId;
         ExpandableNotificationRow row = null;
         if (expandView instanceof ExpandableNotificationRow) {
             row = (ExpandableNotificationRow) expandView;
@@ -4657,10 +4669,13 @@
             // Indicate that the group expansion is changing at this time -- this way the group
             // and children backgrounds / divider animations will look correct.
             row.setGroupExpansionChanging(true);
+            if (row.getStatusBarNotification() != null) {
+                userId = row.getStatusBarNotification().getUserId();
+            }
         }
         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
-        if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
+        if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
             mDraggedDownRow = row;
@@ -4705,10 +4720,20 @@
         mPendingWorkRemoteInputView = clicked;
     }
 
+    private boolean isAnyProfilePublicMode() {
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
-    protected void onWorkChallengeUnlocked() {
-        if (mPendingWorkRemoteInputView != null) {
-            final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+    protected void onWorkChallengeChanged() {
+        updatePublicMode();
+        updateNotifications();
+        if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
             // Expand notification panel and the notification row, then click on remote input view
             final Runnable clickPendingViewRunnable = new Runnable() {
                 @Override
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index da041da..815978e 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2566,6 +2566,12 @@
     // OPEN: Settings > Wireless > Manage wireless plan dialog
     DIALOG_MANAGE_MOBILE_PLAN = 609;
 
+    // ACTION: Logs network type of the device while provisioning
+    PROVISIONING_NETWORK_TYPE = 610;
+
+    // ACTION: Logs action which triggered provisioning.
+    PROVISIONING_ACTION = 611;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0b83e66..54c9afe 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -498,20 +498,6 @@
     }
 
     @Override
-    public void sendAccessibilityEvents(ParceledListSlice events, int userId) {
-        List<AccessibilityEvent> a11yEvents = events.getList();
-        // Grab the lock once for the entire batch
-        synchronized (mLock) {
-            int numEventsToProcess = Math.min(a11yEvents.size(),
-                    AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL);
-            for (int i = 0; i < numEventsToProcess; i++) {
-                AccessibilityEvent event = a11yEvents.get(i);
-                sendAccessibilityEvent(event, userId);
-            }
-        }
-    }
-
-    @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8f16504..e64aa16 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -77,6 +77,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.provider.Settings;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
@@ -1699,6 +1700,7 @@
                 return;
             }
 
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
             try {
                 mConnector.execute("bandwidth", suffix + chain, uid);
                 if (enable) {
@@ -1708,6 +1710,8 @@
                 }
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
         }
     }
@@ -1730,6 +1734,7 @@
                 Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
                 return true;
             }
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "bandwidthEnableDataSaver");
             try {
                 final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
                 if (changed) {
@@ -1741,6 +1746,8 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
                 return false;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
         }
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 547cc51..2bccfee 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2046,25 +2046,30 @@
 
     @Override
     public void setRestrictBackground(boolean restrictBackground) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        final long token = Binder.clearCallingIdentity();
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground");
         try {
-            maybeRefreshTrustedTime();
-            synchronized (mUidRulesFirstLock) {
-                if (restrictBackground == mRestrictBackground) {
-                    // Ideally, UI should never allow this scenario...
-                    Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
-                    return;
+            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                maybeRefreshTrustedTime();
+                synchronized (mUidRulesFirstLock) {
+                    if (restrictBackground == mRestrictBackground) {
+                        // Ideally, UI should never allow this scenario...
+                        Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+                        return;
+                    }
+                    setRestrictBackgroundUL(restrictBackground);
                 }
-                setRestrictBackgroundUL(restrictBackground);
+
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
 
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
+                    .sendToTarget();
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
-
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
-                .sendToTarget();
     }
 
     private void setRestrictBackgroundUL(boolean restrictBackground) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d219aed..353d663 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -872,6 +872,11 @@
                         } catch (RemoteException e) {
                         }
                     }
+                    final Intent lockIntent = new Intent(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+                    lockIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    lockIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                    mContext.sendBroadcastAsUser(lockIntent, UserHandle.SYSTEM,
+                            Manifest.permission.TRUST_LISTENER, /* options */ null);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);