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);