Merge "Update documentation."
diff --git a/core/api/current.txt b/core/api/current.txt
index f126fbf9e..9514447 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2994,6 +2994,7 @@
}
public final class AccessibilityGestureEvent implements android.os.Parcelable {
+ ctor public AccessibilityGestureEvent(int, int, @NonNull java.util.List<android.view.MotionEvent>);
method public int describeContents();
method @NonNull public static String gestureIdToString(int);
method public int getDisplayId();
@@ -3016,6 +3017,7 @@
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method @NonNull public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method @NonNull public final java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getSystemActions();
+ method @NonNull public final android.accessibilityservice.TouchInteractionController getTouchInteractionController(int);
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method @NonNull public final android.util.SparseArray<java.util.List<android.view.accessibility.AccessibilityWindowInfo>> getWindowsOnAllDisplays();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
@@ -3250,6 +3252,31 @@
method public boolean willContinue();
}
+ public final class TouchInteractionController {
+ method public void addListener(@Nullable java.util.concurrent.Executor, @NonNull android.accessibilityservice.TouchInteractionController.Listener);
+ method public int getDisplayId();
+ method public int getMaxPointerCount();
+ method public int getState();
+ method public void performClick();
+ method public void performLongClickAndStartDrag();
+ method public void removeAllListeners();
+ method public boolean removeListener(@NonNull android.accessibilityservice.TouchInteractionController.Listener);
+ method public void requestDelegating();
+ method public void requestDragging(int);
+ method public void requestTouchExploration();
+ method @NonNull public static String stateToString(int);
+ field public static final int STATE_CLEAR = 0; // 0x0
+ field public static final int STATE_DELEGATING = 4; // 0x4
+ field public static final int STATE_DRAGGING = 3; // 0x3
+ field public static final int STATE_TOUCH_EXPLORING = 2; // 0x2
+ field public static final int STATE_TOUCH_INTERACTING = 1; // 0x1
+ }
+
+ public static interface TouchInteractionController.Listener {
+ method public void onMotionEvent(@NonNull android.view.MotionEvent);
+ method public void onStateChanged(int);
+ }
+
}
package android.accounts {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 596b9f15..1c3c7ea 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -318,6 +318,10 @@
method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
}
+ public class SystemConfigManager {
+ method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String);
+ }
+
}
package android.os.storage {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 3046061..bc34c50 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8779,7 +8779,6 @@
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
- method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 226deba..3267473 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -114,6 +114,7 @@
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setStopBackgroundUsersOnSwitch(int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean);
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle();
@@ -128,6 +129,9 @@
field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4
field public static final int PROCESS_STATE_TOP = 2; // 0x2
+ field public static final int STOP_BG_USERS_ON_SWITCH_DEFAULT = -1; // 0xffffffff
+ field public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0; // 0x0
+ field public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1; // 0x1
}
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 768ec38..3c9b232 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -150,7 +150,12 @@
private final int mDisplayId;
private List<MotionEvent> mMotionEvents = new ArrayList<>();
- /** @hide */
+/**
+ * Constructs an AccessibilityGestureEvent to be dispatched to an accessibility service.
+ * @param gestureId the id number of the gesture.
+ * @param displayId the display on which this gesture was performed.
+ * @param motionEvents the motion events that lead to this gesture.
+ */
public AccessibilityGestureEvent(
int gestureId, int displayId, @NonNull List<MotionEvent> motionEvents) {
mGestureId = gestureId;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 61d2b4b..0f852b4 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -53,6 +53,7 @@
import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -65,6 +66,7 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -582,6 +584,10 @@
/** Magnification changed callbacks for different displays */
void onMagnificationChanged(int displayId, @NonNull Region region,
float scale, float centerX, float centerY);
+ /** Callbacks for receiving motion events. */
+ void onMotionEvent(MotionEvent event);
+ /** Callback for tuch state changes. */
+ void onTouchStateChanged(int displayId, int state);
void onSoftKeyboardShowModeChanged(int showMode);
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
void onFingerprintCapturingGesturesChanged(boolean active);
@@ -720,6 +726,12 @@
/** List of magnification controllers, mapping from displayId -> MagnificationController. */
private final SparseArray<MagnificationController> mMagnificationControllers =
new SparseArray<>(0);
+ /**
+ * List of touch interaction controllers, mapping from displayId -> TouchInteractionController.
+ */
+ private final SparseArray<TouchInteractionController> mTouchInteractionControllers =
+ new SparseArray<>(0);
+
private SoftKeyboardController mSoftKeyboardController;
private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
new SparseArray<>(0);
@@ -1194,6 +1206,10 @@
getFingerprintGestureController().onGesture(gesture);
}
+ int getConnectionId() {
+ return mConnectionId;
+ }
+
/**
* Used to control and query the state of display magnification.
*/
@@ -2210,6 +2226,16 @@
}
@Override
+ public void onMotionEvent(MotionEvent event) {
+ AccessibilityService.this.onMotionEvent(event);
+ }
+
+ @Override
+ public void onTouchStateChanged(int displayId, int state) {
+ AccessibilityService.this.onTouchStateChanged(displayId, state);
+ }
+
+ @Override
public void onSoftKeyboardShowModeChanged(int showMode) {
AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
}
@@ -2372,6 +2398,21 @@
}
@Override
+ public void onMotionEvent(MotionEvent event) {
+ final Message message = PooledLambda.obtainMessage(
+ Callbacks::onMotionEvent, mCallback, event);
+ mCaller.sendMessage(message);
+ }
+
+ @Override
+ public void onTouchStateChanged(int displayId, int state) {
+ final Message message = PooledLambda.obtainMessage(Callbacks::onTouchStateChanged,
+ mCallback,
+ displayId, state);
+ mCaller.sendMessage(message);
+ }
+
+ @Override
public void executeMessage(Message message) {
switch (message.what) {
case DO_ON_ACCESSIBILITY_EVENT: {
@@ -2523,7 +2564,7 @@
}
return;
}
- default :
+ default:
Log.w(LOG_TAG, "Unknown message type " + message.what);
}
}
@@ -2748,4 +2789,47 @@
}
}
}
+
+ /**
+ * Returns the touch interaction controller for the specified logical display, which may be used
+ * to detect gestures and otherwise control touch interactions. If
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled the
+ * controller's methods will have no effect.
+ *
+ * @param displayId The logical display id, use {@link Display#DEFAULT_DISPLAY} for default
+ * display.
+ * @return the TouchExploration controller
+ */
+ @NonNull
+ public final TouchInteractionController getTouchInteractionController(int displayId) {
+ synchronized (mLock) {
+ TouchInteractionController controller = mTouchInteractionControllers.get(displayId);
+ if (controller == null) {
+ controller = new TouchInteractionController(this, mLock, displayId);
+ mTouchInteractionControllers.put(displayId, controller);
+ }
+ return controller;
+ }
+ }
+
+ void onMotionEvent(MotionEvent event) {
+ TouchInteractionController controller;
+ synchronized (mLock) {
+ int displayId = event.getDisplayId();
+ controller = mTouchInteractionControllers.get(displayId);
+ }
+ if (controller != null) {
+ controller.onMotionEvent(event);
+ }
+ }
+
+ void onTouchStateChanged(int displayId, int state) {
+ TouchInteractionController controller;
+ synchronized (mLock) {
+ controller = mTouchInteractionControllers.get(displayId);
+ }
+ if (controller != null) {
+ controller.onStateChanged(state);
+ }
+ }
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 58b0d19..651c50f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -22,6 +22,7 @@
import android.view.accessibility.AccessibilityWindowInfo;
import android.accessibilityservice.AccessibilityGestureEvent;
import android.view.KeyEvent;
+import android.view.MotionEvent;
/**
* Top-level interface to an accessibility service component.
@@ -44,6 +45,10 @@
void onMagnificationChanged(int displayId, in Region region, float scale, float centerX, float centerY);
+ void onMotionEvent(in MotionEvent event);
+
+ void onTouchStateChanged(int displayId, int state);
+
void onSoftKeyboardShowModeChanged(int showMode);
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 6c360e5..81457eb 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -122,4 +122,16 @@
oneway void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, in Bundle serializedCallingStackInBundle);
+
+ void setServiceDetectsGesturesEnabled(int displayId, boolean mode);
+
+ void requestTouchExploration(int displayId);
+
+ void requestDragging(int displayId, int pointerId);
+
+ void requestDelegating(int displayId);
+
+ void onDoubleTap(int displayId);
+
+ void onDoubleTapAndHold(int displayId);
}
diff --git a/core/java/android/accessibilityservice/TouchInteractionController.java b/core/java/android/accessibilityservice/TouchInteractionController.java
new file mode 100644
index 0000000..d9be49a
--- /dev/null
+++ b/core/java/android/accessibilityservice/TouchInteractionController.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This class allows a service to handle touch exploration and the detection of specialized
+ * accessibility gestures. The service receives motion events and can match those motion events
+ * against the gestures it supports. The service can also request the framework enter three other
+ * states of operation for the duration of this interaction. Upon entering any of these states the
+ * framework will take over and the service will not receive motion events until the start of a new
+ * interaction. The states are as follows:
+ *
+ * <ul>
+ * <li>The service can tell the framework that this interaction is touch exploration. The user is
+ * trying to explore the screen rather than manipulate it. The framework will then convert the
+ * motion events to hover events to support touch exploration.
+ * <li>The service can tell the framework that this interaction is a dragging interaction where
+ * two fingers are used to execute a one-finger gesture such as scrolling the screen. The
+ * service must specify which of the two fingers should be passed through to rest of the input
+ * pipeline.
+ * <li>Finally, the service can request that the framework delegate this interaction, meaning pass
+ * it through to the rest of the input pipeline as-is.
+ * </ul>
+ *
+ * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE } is enabled, this
+ * controller will receive all motion events received by the framework for the specified display
+ * when not touch-exploring or delegating. If the service classifies this interaction as touch
+ * exploration or delegating the framework will stop sending motion events to the service for the
+ * duration of this interaction. If the service classifies this interaction as a dragging
+ * interaction the framework will send motion events to the service to allow the service to
+ * determine if the interaction still qualifies as dragging or if it has become a delegating
+ * interaction. If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE } is disabled
+ * this controller will not receive any motion events because touch interactions are being passed
+ * through to the input pipeline unaltered.
+ * Note that {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE }
+ * requires setting {@link android.R.attr#canRequestTouchExplorationMode} as well.
+ */
+public final class TouchInteractionController {
+ /** The state where the user is not touching the screen. */
+ public static final int STATE_CLEAR = 0;
+ /**
+ * The state where the user is touching the screen and the service is receiving motion events.
+ */
+ public static final int STATE_TOUCH_INTERACTING = 1;
+ /**
+ * The state where the user is explicitly exploring the screen. The service is not receiving
+ * motion events.
+ */
+ public static final int STATE_TOUCH_EXPLORING = 2;
+ /**
+ * The state where the user is dragging with two fingers. The service is not receiving motion
+ * events. The selected finger is being dispatched to the rest of the input pipeline to execute
+ * the drag.
+ */
+ public static final int STATE_DRAGGING = 3;
+ /**
+ * The user is performing a gesture which is being passed through to the input pipeline as-is.
+ * The service is not receiving motion events.
+ */
+ public static final int STATE_DELEGATING = 4;
+
+ @IntDef({
+ STATE_CLEAR,
+ STATE_TOUCH_INTERACTING,
+ STATE_TOUCH_EXPLORING,
+ STATE_DRAGGING,
+ STATE_DELEGATING
+ })
+ private @interface State {}
+
+ // The maximum number of pointers that can be touching the screen at once. (See MAX_POINTER_ID
+ // in frameworks/native/include/input/Input.h)
+ private static final int MAX_POINTER_COUNT = 32;
+
+ private final AccessibilityService mService;
+ private final Object mLock;
+ private final int mDisplayId;
+ private boolean mServiceDetectsGestures;
+ /** Map of listeners to executors. Lazily created when adding the first listener. */
+ private ArrayMap<Listener, Executor> mListeners;
+
+ // The current state of the display.
+ private int mState = STATE_CLEAR;
+
+ TouchInteractionController(
+ @NonNull AccessibilityService service, @NonNull Object lock, int displayId) {
+ mDisplayId = displayId;
+ mLock = lock;
+ mService = service;
+ }
+
+ /**
+ * Adds the specified change listener to the list of motion event listeners. The callback will
+ * run using on the specified {@link Executor}', or on the service's main thread if the
+ * Executor is {@code null}.
+ * @param listener the listener to add, must be non-null
+ * @param executor the executor for this callback, or {@code null} to execute on the service's
+ * main thread
+ */
+ public void addListener(@Nullable Executor executor, @NonNull Listener listener) {
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
+ mListeners.put(listener, executor);
+ if (mListeners.size() == 1) {
+ setServiceDetectsGestures(true);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified listener from the list of motion event listeners.
+ *
+ * @param listener the listener to remove, must be non-null
+ * @return {@code true} if the listener was removed, {@code false} otherwise
+ */
+ public boolean removeListener(@NonNull Listener listener) {
+ if (mListeners == null) {
+ return false;
+ }
+ synchronized (mLock) {
+ boolean result = mListeners.remove(listener) != null;
+ if (result && mListeners.size() == 0) {
+ setServiceDetectsGestures(false);
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Removes all listeners and returns control of touch interactions to the framework.
+ */
+ public void removeAllListeners() {
+ if (mListeners != null) {
+ synchronized (mLock) {
+ mListeners.clear();
+ setServiceDetectsGestures(false);
+ }
+ }
+ }
+
+ /**
+ * Dispatches motion events to any registered listeners. This should be called on the service's
+ * main thread.
+ */
+ void onMotionEvent(MotionEvent event) {
+ final ArrayMap<Listener, Executor> entries;
+ synchronized (mLock) {
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final Listener listener = entries.keyAt(i);
+ final Executor executor = entries.valueAt(i);
+ if (executor != null) {
+ executor.execute(() -> listener.onMotionEvent(event));
+ } else {
+ // We're already on the main thread, just run the listener.
+ listener.onMotionEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Dispatches motion events to any registered listeners. This should be called on the service's
+ * main thread.
+ */
+ void onStateChanged(@State int state) {
+ mState = state;
+ final ArrayMap<Listener, Executor> entries;
+ synchronized (mLock) {
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final Listener listener = entries.keyAt(i);
+ final Executor executor = entries.valueAt(i);
+ if (executor != null) {
+ executor.execute(() -> listener.onStateChanged(state));
+ } else {
+ // We're already on the main thread, just run the listener.
+ listener.onStateChanged(state);
+ }
+ }
+ }
+
+ /**
+ * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this
+ * controller will receive all motion events received by the framework for the specified display
+ * when not touch-exploring, delegating, or dragging. This allows the service to detect its own
+ * gestures, and use its own logic to judge when the framework should start touch-exploring,
+ * delegating, or dragging. If {@link
+ * AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE } is disabled this flag has no
+ * effect.
+ *
+ * @see AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+ */
+ private void setServiceDetectsGestures(boolean mode) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.setServiceDetectsGesturesEnabled(mDisplayId, mode);
+ mServiceDetectsGestures = mode;
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at
+ * least one listener has been added for this display this function tells the framework to
+ * initiate touch exploration. Touch exploration will continue for the duration of this
+ * interaction.
+ */
+ public void requestTouchExploration() {
+ checkState();
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.requestTouchExploration(mDisplayId);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
+ * one listener has been added, this function tells the framework to initiate a dragging
+ * interaction using the specified pointer. The pointer's movements will be passed through to
+ * the rest of the input pipeline. Dragging is often used to perform two-finger scrolling.
+ *
+ * @param pointerId the pointer to be passed through to the rest of the input pipeline. If the
+ * pointer id is valid but not actually present on the screen it will be ignored.
+ * @throws IllegalArgumentException if the pointer id is outside of the allowed range.
+ */
+ public void requestDragging(int pointerId) {
+ checkState();
+ if (pointerId < 0 || pointerId > MAX_POINTER_COUNT) {
+ throw new IllegalArgumentException("Invalid pointer id: " + pointerId);
+ }
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.requestDragging(mDisplayId, pointerId);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
+ * one listener has been added, this function tells the framework to initiate a delegating
+ * interaction. Motion events will be passed through as-is to the rest of the input pipeline for
+ * the duration of this interaction.
+ */
+ public void requestDelegating() {
+ checkState();
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.requestDelegating(mDisplayId);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
+ * one listener has been added, this function tells the framework to perform a click.
+ * The framework will first try to perform
+ * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_CLICK} on the item with
+ * accessibility focus. If that fails, the framework will simulate a click using motion events
+ * on the last location to have accessibility focus.
+ */
+ public void performClick() {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.onDoubleTap(mDisplayId);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
+ * one listener has been added, this function tells the framework to perform a long click.
+ * The framework will simulate a long click using motion events on the last location with
+ * accessibility focus and will delegate any movements to the rest of the input pipeline. This
+ * allows a user to double-tap and hold to trigger a drag and then execute that drag by moving
+ * their finger.
+ */
+ public void performLongClickAndStartDrag() {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mService.getConnectionId());
+ if (connection != null) {
+ try {
+ connection.onDoubleTapAndHold(mDisplayId);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ private void checkState() {
+ if (!mServiceDetectsGestures || mListeners.size() == 0) {
+ throw new IllegalStateException(
+ "State transitions are not allowed without first adding a listener.");
+ }
+ if (mState != STATE_TOUCH_INTERACTING) {
+ throw new IllegalStateException(
+ "State transitions are not allowed in " + stateToString(mState));
+ }
+ }
+
+ /** @return the maximum number of pointers that this display will accept. */
+ public int getMaxPointerCount() {
+ return MAX_POINTER_COUNT;
+ }
+
+ /** @return the display id associated with this controller. */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * @return the current state of this controller.
+ * @see TouchInteractionController#STATE_CLEAR
+ * @see TouchInteractionController#STATE_DELEGATING
+ * @see TouchInteractionController#STATE_DRAGGING
+ * @see TouchInteractionController#STATE_TOUCH_EXPLORING
+ */
+ public int getState() {
+ synchronized (mLock) {
+ return mState;
+ }
+ }
+
+ /** Returns a string representation of the specified state. */
+ @NonNull
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_CLEAR:
+ return "STATE_CLEAR";
+ case STATE_TOUCH_INTERACTING:
+ return "STATE_TOUCH_INTERACTING";
+ case STATE_TOUCH_EXPLORING:
+ return "STATE_TOUCH_EXPLORING";
+ case STATE_DRAGGING:
+ return "STATE_DRAGGING";
+ case STATE_DELEGATING:
+ return "STATE_DELEGATING";
+ default:
+ return "Unknown state: " + state;
+ }
+ }
+
+ /** Listeners allow services to receive motion events and state change updates. */
+ public interface Listener {
+ /**
+ * Called when the framework has sent a motion event to the service.
+ *
+ * @param event the event being passed to the service.
+ */
+ void onMotionEvent(@NonNull MotionEvent event);
+
+ /**
+ * Called when the state of motion event dispatch for this display has changed.
+ *
+ * @param state the new state of motion event dispatch.
+ * @see TouchInteractionController#STATE_CLEAR
+ * @see TouchInteractionController#STATE_DELEGATING
+ * @see TouchInteractionController#STATE_DRAGGING
+ * @see TouchInteractionController#STATE_TOUCH_EXPLORING
+ */
+ void onStateChanged(@State int state);
+ }
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 365493de..d77227b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4082,6 +4082,56 @@
}
/**
+ * Uses the value defined by the platform.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_DEFAULT = -1;
+
+ /**
+ * Overrides value defined by the platform and stop background users on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1;
+
+ /**
+ * Overrides value defined by the platform and don't stop background users on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0;
+
+ /** @hide */
+ @IntDef(prefix = { "STOP_BG_USERS_ON_SWITCH_" }, value = {
+ STOP_BG_USERS_ON_SWITCH_DEFAULT,
+ STOP_BG_USERS_ON_SWITCH_TRUE,
+ STOP_BG_USERS_ON_SWITCH_FALSE
+ })
+ public @interface StopBgUsersOnSwitch {}
+
+ /**
+ * Sets whether background users should be stopped when the current user is switched.
+ *
+ * <p>Should only be used on tests.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ try {
+ getService().setStopBackgroundUsersOnSwitch(value);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starts a profile.
* To be used with non-managed profiles, managed profiles should use
* {@link UserManager#requestQuietModeEnabled}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0881db0..7dbcd5f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -686,6 +688,11 @@
@Nullable VoiceInteractionManagerProvider provider);
/**
+ * Sets whether background users should be stopped when the current user is switched.
+ */
+ public abstract void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value);
+
+ /**
* Provides the interface to communicate between voice interaction manager service and
* ActivityManagerService.
*/
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 658c130..de79a64 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -349,6 +349,7 @@
@UnsupportedAppUsage
boolean switchUser(int userid);
@UnsupportedAppUsage
+ void setStopBackgroundUsersOnSwitch(int value);
boolean removeTask(int taskId);
@UnsupportedAppUsage
void registerProcessObserver(in IProcessObserver observer);
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 65f71d0..828b171 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -49,6 +49,7 @@
import android.view.Display;
import android.view.InputEvent;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
@@ -1542,6 +1543,15 @@
return false;
}
+ public void onMotionEvent(MotionEvent event) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onTouchStateChanged(int displayId, int state) {
+ /* do nothing */
+ }
+
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
final OnAccessibilityEventListener listener;
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 2a344f6..ad3de25 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -103,7 +103,7 @@
* are unparcelled, mParcelledData willbe set to null.
*/
@UnsupportedAppUsage
- Parcel mParcelledData = null;
+ volatile Parcel mParcelledData = null;
/**
* Whether {@link #mParcelledData} was generated by native code or not.
@@ -182,13 +182,56 @@
* @param b a Bundle to be copied.
*/
BaseBundle(BaseBundle b) {
- copyInternal(b, false);
+ this(b, /* deep */ false);
}
/**
- * Special constructor that does not initialize the bundle.
+ * Constructs a {@link BaseBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- BaseBundle(boolean doInit) {
+ BaseBundle(BaseBundle from, boolean deep) {
+ synchronized (from) {
+ mClassLoader = from.mClassLoader;
+
+ if (from.mMap != null) {
+ if (!deep) {
+ mMap = new ArrayMap<>(from.mMap);
+ } else {
+ final ArrayMap<String, Object> fromMap = from.mMap;
+ final int n = fromMap.size();
+ mMap = new ArrayMap<>(n);
+ for (int i = 0; i < n; i++) {
+ mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
+ }
+ }
+ } else {
+ mMap = null;
+ }
+
+ final Parcel parcelledData;
+ if (from.mParcelledData != null) {
+ if (from.isEmptyParcel()) {
+ parcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
+ mParcelledByNative = false;
+ } else {
+ parcelledData = Parcel.obtain();
+ parcelledData.appendFrom(from.mParcelledData, 0,
+ from.mParcelledData.dataSize());
+ parcelledData.setDataPosition(0);
+ mParcelledByNative = from.mParcelledByNative;
+ }
+ } else {
+ parcelledData = null;
+ mParcelledByNative = false;
+ }
+
+ // Keep as last statement to ensure visibility of other fields
+ mParcelledData = parcelledData;
+ }
}
/**
@@ -323,8 +366,8 @@
} else {
mMap.erase();
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
return;
}
@@ -358,8 +401,8 @@
if (recycleParcel) {
recycleParcel(parcelledData);
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
}
if (DEBUG) {
Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
@@ -501,44 +544,7 @@
mMap.clear();
}
- void copyInternal(BaseBundle from, boolean deep) {
- synchronized (from) {
- if (from.mParcelledData != null) {
- if (from.isEmptyParcel()) {
- mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
- } else {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(from.mParcelledData, 0,
- from.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
- mParcelledByNative = from.mParcelledByNative;
- }
- } else {
- mParcelledData = null;
- mParcelledByNative = false;
- }
-
- if (from.mMap != null) {
- if (!deep) {
- mMap = new ArrayMap<>(from.mMap);
- } else {
- final ArrayMap<String, Object> fromMap = from.mMap;
- final int N = fromMap.size();
- mMap = new ArrayMap<>(N);
- for (int i = 0; i < N; i++) {
- mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
- }
- }
- } else {
- mMap = null;
- }
-
- mClassLoader = from.mClassLoader;
- }
- }
-
- Object deepCopyValue(Object value) {
+ private Object deepCopyValue(Object value) {
if (value == null) {
return null;
}
@@ -570,7 +576,7 @@
return value;
}
- ArrayList deepcopyArrayList(ArrayList from) {
+ private ArrayList deepcopyArrayList(ArrayList from) {
final int N = from.size();
ArrayList out = new ArrayList(N);
for (int i=0; i<N; i++) {
@@ -1717,9 +1723,9 @@
if (length < 0) {
throw new RuntimeException("Bad length in parcel: " + length);
} else if (length == 0) {
+ mParcelledByNative = false;
// Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
return;
} else if (length % 4 != 0) {
throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
@@ -1757,8 +1763,8 @@
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);
- mParcelledData = p;
mParcelledByNative = isNativeBundle;
+ mParcelledData = p;
}
/** {@hide} */
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b677b69..b069fb3 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -53,7 +53,7 @@
*
* <p>Most developers will not implement this class directly, instead using the
* <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired
- * interface, having it generate the appropriate Binder subclass. You can,
+ * interface, having it generate the appropriate Binder subclass. You can,
* however, derive directly from Binder to implement your own custom RPC
* protocol or simply instantiate a raw Binder object directly to use as a
* token that can be shared across processes.
@@ -63,17 +63,17 @@
* To use this correctly, you must be doing so within the context of a top-level
* application component (a {@link android.app.Service}, {@link android.app.Activity},
* or {@link android.content.ContentProvider}) that lets the system know your process
- * should remain running.</p>
+ * should remain running.
*
* <p>You must keep in mind the situations in which your process
* could go away, and thus require that you later re-create a new Binder and re-attach
- * it when the process starts again. For example, if you are using this within an
+ * it when the process starts again. For example, if you are using this within an
* {@link android.app.Activity}, your activity's process may be killed any time the
* activity is not started; if the activity is later re-created you will need to
* create a new Binder and hand it back to the correct place again; you need to be
* aware that your process may be started for another reason (for example to receive
* a broadcast) that will not involve re-creating the activity and thus run its code
- * to create a new Binder.</p>
+ * to create a new Binder.
*
* @see IBinder
*/
@@ -94,14 +94,15 @@
/**
* Value to represents that a calling work source is not set.
*
- * This constatnt needs to be kept in sync with IPCThreadState::kUnsetWorkSource.
+ * <p>This constant needs to be kept in sync with IPCThreadState::kUnsetWorkSource.
*
* @hide
*/
public static final int UNSET_WORKSOURCE = -1;
/**
- * Control whether dump() calls are allowed.
+ * Control whether {@link #dump(FileDescriptor, PrintWriter, String[]) dump()}
+ * calls are allowed.
*/
private static volatile String sDumpDisabled = null;
@@ -188,7 +189,7 @@
sObserver = observer;
}
- /** {@hide} */
+ /** @hide */
static volatile boolean sWarnOnBlocking = false;
/**
@@ -207,8 +208,8 @@
/**
* Allow blocking calls on the given interface, overriding the requested
* value of {@link #setWarnOnBlocking(boolean)}.
- * <p>
- * This should only be rarely called when you are <em>absolutely sure</em>
+ *
+ * <p>This should only be rarely called when you are <em>absolutely sure</em>
* the remote interface is a built-in system component that can never be
* upgraded. In particular, this <em>must never</em> be called for
* interfaces hosted by package that could be upgraded or replaced,
@@ -258,7 +259,9 @@
ThreadLocal.withInitial(() -> sWarnOnBlocking);
/**
- * Allow blocking calls for the current thread. See {@link #allowBlocking}.
+ * Allow blocking calls for the current thread.
+ *
+ * @see {@link #allowBlocking}.
*
* @hide
*/
@@ -267,7 +270,9 @@
}
/**
- * Reset the current thread to the default blocking behavior. See {@link #defaultBlocking}.
+ * Reset the current thread to the default blocking behavior.
+ *
+ * @see {@link #defaultBlocking}.
*
* @hide
*/
@@ -286,10 +291,10 @@
/**
* Return the ID of the process that sent you the current transaction
- * that is being processed. This pid can be used with higher-level
+ * that is being processed. This PID can be used with higher-level
* system services to determine its identity and check permissions.
* If the current thread is not currently executing an incoming transaction,
- * then its own pid is returned.
+ * then its own PID is returned.
*
* Warning: oneway transactions do not receive PID.
*/
@@ -297,11 +302,11 @@
public static final native int getCallingPid();
/**
- * Return the Linux uid assigned to the process that sent you the
- * current transaction that is being processed. This uid can be used with
+ * Return the Linux UID assigned to the process that sent you the
+ * current transaction that is being processed. This UID can be used with
* higher-level system services to determine its identity and check
- * permissions. If the current thread is not currently executing an
- * incoming transaction, then its own uid is returned.
+ * permissions. If the current thread is not currently executing an
+ * incoming transaction, then its own UID is returned.
*/
@CriticalNative
public static final native int getCallingUid();
@@ -316,11 +321,11 @@
public static final native boolean isDirectlyHandlingTransaction();
/**
- * Return the Linux uid assigned to the process that sent the transaction
+ * Return the Linux UID assigned to the process that sent the transaction
* currently being processed.
*
* @throws IllegalStateException if the current thread is not currently
- * executing an incoming transaction.
+ * executing an incoming transaction.
*/
public static final int getCallingUidOrThrow() {
if (!isDirectlyHandlingTransaction()) {
@@ -332,18 +337,20 @@
/**
* Return the UserHandle assigned to the process that sent you the
- * current transaction that is being processed. This is the user
- * of the caller. It is distinct from {@link #getCallingUid()} in that a
+ * current transaction that is being processed. This is the user
+ * of the caller. It is distinct from {@link #getCallingUid()} in that a
* particular user will have multiple distinct apps running under it each
- * with their own uid. If the current thread is not currently executing an
+ * with their own UID. If the current thread is not currently executing an
* incoming transaction, then its own UserHandle is returned.
+ *
+ * @see UserHandle
*/
public static final @NonNull UserHandle getCallingUserHandle() {
return UserHandle.of(UserHandle.getUserId(getCallingUid()));
}
/**
- * Reset the identity of the incoming IPC on the current thread. This can
+ * Reset the identity of the incoming IPC on the current thread. This can
* be useful if, while handling an incoming call, you will be calling
* on interfaces of other objects that may be local to your process and
* need to do permission checks on the calls coming into them (so they
@@ -376,10 +383,10 @@
/**
* Convenience method for running the provided action enclosed in
- * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}
+ * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}.
*
- * Any exception thrown by the given action will be caught and rethrown after the call to
- * {@link #restoreCallingIdentity}
+ * <p>Any exception thrown by the given action will be caught and
+ * rethrown after the call to {@link #restoreCallingIdentity}.
*
* @hide
*/
@@ -400,10 +407,10 @@
/**
* Convenience method for running the provided action enclosed in
- * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result
+ * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result.
*
- * Any exception thrown by the given action will be caught and rethrown after the call to
- * {@link #restoreCallingIdentity}
+ * <p>Any exception thrown by the given action will be caught and rethrown after
+ * the call to {@link #restoreCallingIdentity}.
*
* @hide
*/
@@ -428,12 +435,13 @@
*
* <p>The StrictMode settings are kept in two places: a Java-level
* threadlocal for libcore/Dalvik, and a native threadlocal (set
- * here) for propagation via Binder calls. This is a little
+ * here) for propagation via Binder calls. This is a little
* unfortunate, but necessary to break otherwise more unfortunate
* dependencies either of Dalvik on Android, or Android
* native-only code on Dalvik.
*
* @see StrictMode
+ *
* @hide
*/
@CriticalNative
@@ -443,6 +451,7 @@
* Gets the current native thread-local StrictMode policy mask.
*
* @see #setThreadStrictModePolicy
+ *
* @hide
*/
@CriticalNative
@@ -459,7 +468,7 @@
* reasons, we only support one UID. This UID represents the original user responsible for the
* binder calls.
*
- * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after setting the
+ * <p>{@link #restoreCallingWorkSource(long)} must always be called after setting the
* worksource.
*
* <p>A typical use case would be
@@ -477,16 +486,16 @@
*
* @param workSource The original UID responsible for the binder call.
* @return token to restore original work source.
- **/
+ */
@CriticalNative
public static final native long setCallingWorkSourceUid(int workSource);
/**
* Returns the work source set by the caller.
*
- * Unlike {@link Binder#getCallingUid()}, this result of this method cannot be trusted. The
+ * <p>Unlike {@link #getCallingUid()}, this result of this method cannot be trusted. The
* caller can set the value to whatever they want. Only use this value if you trust the calling
- * uid.
+ * UID.
*
* @return The original UID responsible for the binder transaction.
*/
@@ -499,7 +508,7 @@
* <p>The work source will be propagated for future outgoing binder transactions
* executed on this thread.
*
- * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after clearing the
+ * <p>{@link #restoreCallingWorkSource(long)} must always be called after clearing the
* worksource.
*
* <p>A typical use case would be
@@ -513,13 +522,13 @@
* </pre>
*
* @return token to restore original work source.
- **/
+ */
@CriticalNative
public static final native long clearCallingWorkSource();
/**
* Restores the work source on this thread using a token returned by
- * {@link #setCallingWorkSourceUid(int) or {@link clearCallingWorkSource()}.
+ * {@link #setCallingWorkSourceUid(int)} or {@link #clearCallingWorkSource()}.
*
* <p>A typical use case would be
* <pre>
@@ -530,7 +539,7 @@
* Binder.restoreCallingWorkSource(token);
* }
* </pre>
- **/
+ */
@CriticalNative
public static final native void restoreCallingWorkSource(long token);
@@ -553,7 +562,7 @@
* Use a VINTF-stability binder w/o VINTF requirements. Should be called
* on a binder before it is sent out of process.
*
- * This must be called before the object is sent to another process.
+ * <p>This must be called before the object is sent to another process.
*
* @hide
*/
@@ -561,7 +570,7 @@
/**
* Flush any Binder commands pending in the current thread to the kernel
- * driver. This can be
+ * driver. This can be
* useful to call before performing an operation that may block for a long
* time, to ensure that any pending object references have been released
* in order to prevent the process from holding on to objects longer than
@@ -570,7 +579,7 @@
public static final native void flushPendingCommands();
/**
- * Add the calling thread to the IPC thread pool. This function does
+ * Add the calling thread to the IPC thread pool. This function does
* not return until the current process is exiting.
*/
public static final void joinThreadPool() {
@@ -579,6 +588,7 @@
/**
* Returns true if the specified interface is a proxy.
+ *
* @hide
*/
public static final boolean isProxy(IInterface iface) {
@@ -588,6 +598,7 @@
/**
* Call blocks until the number of executing binder threads is less
* than the maximum number of binder threads allowed for this process.
+ *
* @hide
*/
public static final native void blockUntilThreadAvailable();
@@ -595,7 +606,7 @@
/**
* Default constructor just initializes the object.
*
- * If you're creating a Binder token (a Binder object without an attached interface),
+ * <p>If you're creating a Binder token (a Binder object without an attached interface),
* you should use {@link #Binder(String)} instead.
*/
public Binder() {
@@ -605,7 +616,7 @@
/**
* Constructor for creating a raw Binder object (token) along with a descriptor.
*
- * The descriptor of binder objects usually specifies the interface they are implementing.
+ * <p>The descriptor of binder objects usually specifies the interface they are implementing.
* In case of binder tokens, no interface is implemented, and the descriptor can be used
* as a sort of tag to help identify the binder token. This will help identify remote
* references to these objects more easily when debugging.
@@ -614,7 +625,7 @@
* Instead of creating multiple tokens with the same descriptor, consider adding a suffix to
* help identify them.
*/
- public Binder(@Nullable String descriptor) {
+ public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
@@ -631,9 +642,9 @@
/**
* Convenience method for associating a specific interface with the Binder.
- * After calling, queryLocalInterface() will be implemented for you
- * to return the given owner IInterface when the corresponding
- * descriptor is requested.
+ * After calling, {@link #queryLocalInterface(String) queryLocalInterface()}
+ * will be implemented for you to return the given owner IInterface when
+ * the corresponding descriptor is requested.
*/
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
@@ -666,8 +677,8 @@
}
/**
- * Use information supplied to attachInterface() to return the
- * associated IInterface if it matches the requested
+ * Use information supplied to {@link #attachInterface attachInterface()}
+ * to return the associated {@link IInterface} if it matches the requested
* descriptor.
*/
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
@@ -678,14 +689,15 @@
}
/**
- * Control disabling of dump calls in this process. This is used by the system
+ * Control disabling of dump calls in this process. This is used by the system
* process watchdog to disable incoming dump calls while it has detecting the system
- * is hung and is reporting that back to the activity controller. This is to
+ * is hung and is reporting that back to the activity controller. This is to
* prevent the controller from getting hung up on bug reports at this point.
- * @hide
*
* @param msg The message to show instead of the dump; if null, dumps are
* re-enabled.
+ *
+ * @hide
*/
public static void setDumpDisabled(String msg) {
sDumpDisabled = msg;
@@ -694,7 +706,8 @@
/**
* Listener to be notified about each proxy-side binder call.
*
- * See {@link setProxyTransactListener}.
+ * @see {@link #setProxyTransactListener}.
+ *
* @hide
*/
@SystemApi
@@ -702,7 +715,8 @@
/**
* Called before onTransact.
*
- * @return an object that will be passed back to #onTransactEnded (or null).
+ * @return an object that will be passed back to {@link #onTransactEnded} (or null).,
+ *
* @hide
*/
@Nullable
@@ -713,15 +727,15 @@
/**
* Called before onTransact.
*
- * @return an object that will be passed back to #onTransactEnded (or null).
+ * @return an object that will be passed back to {@link #onTransactEnded} (or null).
*/
@Nullable
Object onTransactStarted(@NonNull IBinder binder, int transactionCode);
/**
- * Called after onTranact (even when an exception is thrown).
+ * Called after onTransact (even when an exception is thrown).
*
- * @param session The object return by #onTransactStarted.
+ * @param session The object return by {@link #onTransactStarted}.
*/
void onTransactEnded(@Nullable Object session);
}
@@ -732,16 +746,17 @@
* <li>By default, this listener will propagate the worksource if the outgoing call happens on
* the same thread as the incoming binder call.
* <li>Custom attribution can be done by calling {@link ThreadLocalWorkSource#setUid(int)}.
+ *
* @hide
*/
public static class PropagateWorkSourceTransactListener implements ProxyTransactListener {
@Override
public Object onTransactStarted(IBinder binder, int transactionCode) {
- // Note that {@link Binder#getCallingUid()} is already set to the UID of the current
- // process when this method is called.
- //
- // We use ThreadLocalWorkSource instead. It also allows feature owners to set
- // {@link ThreadLocalWorkSource#set(int) manually to attribute resources to a UID.
+ // Note that {@link #getCallingUid()} is already set to the UID of the current
+ // process when this method is called.
+ //
+ // We use {@link ThreadLocalWorkSource} instead. It also allows feature owners to set
+ // {@link ThreadLocalWorkSource#set(int)} manually to attribute resources to a UID.
int uid = ThreadLocalWorkSource.getUid();
if (uid != ThreadLocalWorkSource.UID_NONE) {
return Binder.setCallingWorkSourceUid(uid);
@@ -770,6 +785,7 @@
* <li>The listener is called on the critical path of the binder transaction so be careful about
* performance.
* <li>Never execute another binder transaction inside the listener.
+ *
* @hide
*/
@SystemApi
@@ -778,7 +794,7 @@
}
/**
- * Default implementation is a stub that returns false. You will want
+ * Default implementation is a stub that returns false. You will want
* to override this to do the appropriate unmarshalling of transactions.
*
* <p>If you want to call this, call transact().
@@ -786,15 +802,14 @@
* <p>Implementations that are returning a result should generally use
* {@link Parcel#writeNoException() Parcel.writeNoException} and
* {@link Parcel#writeException(Exception) Parcel.writeException} to propagate
- * exceptions back to the caller.</p>
+ * exceptions back to the caller.
*
- * @param code The action to perform. This should
- * be a number between {@link #FIRST_CALL_TRANSACTION} and
- * {@link #LAST_CALL_TRANSACTION}.
+ * @param code The action to perform. This should be a number between
+ * {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}.
* @param data Marshalled data being received from the caller.
* @param reply If the caller is expecting a result back, it should be marshalled
* in to here.
- * @param flags Additional operation flags. Either 0 for a normal
+ * @param flags Additional operation flags. Either 0 for a normal
* RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
*
* @return Return true on a successful call; returning false is generally used to
@@ -856,10 +871,12 @@
* Resolves a transaction code to a human readable name.
*
* <p>Default implementation is a stub that returns null.
+ *
* <p>AIDL generated code will return the original method name.
*
* @param transactionCode The code to resolve.
* @return A human readable name.
+ *
* @hide
*/
public @Nullable String getTransactionName(int transactionCode) {
@@ -925,7 +942,7 @@
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
- * @param fout The file to which you should dump your state. This will be
+ * @param fout The file to which you should dump your state. This will be
* closed for you after you return.
* @param args additional arguments to the dump request.
*/
@@ -941,6 +958,7 @@
* @param callback Callback through which to interact with the invoking shell.
* @param resultReceiver Called when the command has finished executing, with the result code.
* @throws RemoteException
+ *
* @hide
*/
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -958,7 +976,8 @@
*
* <p class="caution">Note: no permission checking is done before calling this method; you must
* apply any security checks as appropriate for the command being executed.
- * Consider using {@link ShellCommand} to help in the implementation.</p>
+ * Consider using {@link ShellCommand} to help in the implementation.
+ *
* @hide
*/
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -1013,7 +1032,7 @@
* System services can implement this method to implement ADB shell commands.
*
* <p>A system binder service can implement it to handle shell commands on ADB. For example,
- * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>.
+ * the Job Scheduler service implements it to handle {@code adb shell cmd jobscheduler}.
*
* <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and
* {@link Process#ROOT_UID} can call them.
@@ -1022,8 +1041,8 @@
* @param out standard output
* @param err standard error
* @param args arguments passed to the command. Can be empty. The first argument is typically
- * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
- * @return the status code returned from the <code>cmd</code> command.
+ * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
+ * @return the status code returned from the {@code cmd} command.
*
* @hide
*/
@@ -1051,7 +1070,7 @@
public final native void setExtension(@Nullable IBinder extension);
/**
- * Default implementation rewinds the parcels and calls onTransact. On
+ * Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
@@ -1083,7 +1102,7 @@
static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
- // Trying to send > 800k, this is way too much
+ // Trying to send > 800k, this is way too much.
StringBuilder sb = new StringBuilder();
sb.append(msg);
sb.append(": on ");
@@ -1107,7 +1126,7 @@
private static native long getNativeBBinderHolder();
/**
- * By default, we use the calling uid since we can always trust it.
+ * By default, we use the calling UID since we can always trust it.
*/
private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider =
(x) -> Binder.getCallingUid();
@@ -1122,6 +1141,7 @@
* <li>The callback is called on the critical path of the binder transaction so be careful about
* performance.
* <li>Never execute another binder transaction inside the callback.
+ *
* @hide
*/
public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) {
@@ -1131,12 +1151,12 @@
sWorkSourceProvider = workSourceProvider;
}
- // Entry point from android_util_Binder.cpp's onTransact
+ // Entry point from android_util_Binder.cpp's onTransact.
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
// At that point, the parcel request headers haven't been parsed so we do not know what
- // WorkSource the caller has set. Use calling uid as the default.
+ // {@link WorkSource} the caller has set. Use calling UID as the default.
final int callingUid = Binder.getCallingUid();
final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
try {
@@ -1154,17 +1174,18 @@
observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
- // theoretically, we should call transact, which will call onTransact,
+ // Theoretically, we should call transact, which will call onTransact,
// but all that does is rewind it, and we just got these from an IPC,
// so we'll just call it directly.
boolean res;
// Log any exceptions as warnings, don't silently suppress them.
- // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
+ // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions
+ // disappear into the ether.
final boolean tracingEnabled = Binder.isTracingEnabled();
try {
final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
if (heavyHitterWatcher != null) {
- // Notify the heavy hitter watcher, if it's enabled
+ // Notify the heavy hitter watcher, if it's enabled.
heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
}
if (tracingEnabled) {
@@ -1197,7 +1218,7 @@
Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
}
} else {
- // Clear the parcel before writing the exception
+ // Clear the parcel before writing the exception.
reply.setDataSize(0);
reply.setDataPosition(0);
reply.writeException(e);
@@ -1209,7 +1230,7 @@
}
if (observer != null) {
// The parcel RPC headers have been called during onTransact so we can now access
- // the worksource uid from the parcel.
+ // the worksource UID from the parcel.
final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid(
data.readCallingWorkSourceUid());
observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid);
@@ -1220,9 +1241,9 @@
data.recycle();
// Just in case -- we are done with the IPC, so there should be no more strict
- // mode violations that have gathered for this thread. Either they have been
+ // mode violations that have gathered for this thread. Either they have been
// parceled and are now in transport off to the caller, or we are returning back
- // to the main transaction loop to wait for another incoming transaction. Either
+ // to the main transaction loop to wait for another incoming transaction. Either
// way, strict mode begone!
StrictMode.clearGatheredViolations();
return res;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 92eb7a5..b2bbfd6 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -102,6 +102,18 @@
}
/**
+ * Constructs a {@link Bundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
+ */
+ Bundle(Bundle from, boolean deep) {
+ super(from, deep);
+ }
+
+ /**
* If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast.
* Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN}
* unset, because scanning a map is slower. We'll do it lazily in
@@ -167,13 +179,6 @@
}
/**
- * Constructs a Bundle without initializing it.
- */
- Bundle(boolean doInit) {
- super(doInit);
- }
-
- /**
* Make a Bundle for a single key/value pair.
*
* @hide
@@ -260,9 +265,7 @@
* are referenced as-is and not copied in any way.
*/
public Bundle deepCopy() {
- Bundle b = new Bundle(false);
- b.copyInternal(this, true);
- return b;
+ return new Bundle(this, /* deep */ true);
}
/**
@@ -324,28 +327,10 @@
*/
public boolean hasFileDescriptors() {
if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
- boolean fdFound = false; // keep going until we find one or run out of data
-
- if (mParcelledData != null) {
- if (mParcelledData.hasFileDescriptors()) {
- fdFound = true;
- }
- } else {
- // It's been unparcelled, so we need to walk the map
- for (int i=mMap.size()-1; i>=0; i--) {
- Object obj = mMap.valueAt(i);
- if (Parcel.hasFileDescriptors(obj)) {
- fdFound = true;
- break;
- }
- }
- }
-
- if (fdFound) {
- mFlags |= FLAG_HAS_FDS;
- } else {
- mFlags &= ~FLAG_HAS_FDS;
- }
+ Parcel p = mParcelledData;
+ mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap))
+ ? mFlags | FLAG_HAS_FDS
+ : mFlags & ~FLAG_HAS_FDS;
mFlags |= FLAG_HAS_FDS_KNOWN;
}
return (mFlags & FLAG_HAS_FDS) != 0;
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index d83d94a..15e3ce2 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.content.ComponentName;
+
/**
* Binder interface to query SystemConfig in the system server.
* {@hide}
@@ -44,5 +46,5 @@
/**
* @see SystemConfigManager#getEnabledComponentOverrides
*/
- List<String> getEnabledComponentOverrides(String packageName);
+ List<ComponentName> getEnabledComponentOverrides(String packageName);
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index dd0cb8c..d1e6716 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -747,57 +747,70 @@
}
/**
- * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
- * has file descriptors.
+ * Check if the object has file descriptors.
+ *
+ * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link
+ * #writeValue(Object)}}
*
* <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method
* for that.
*
- * @throws IllegalArgumentException if you provide any object not supported by above methods.
- * Most notably, if you pass {@link Parcel}, this method will throw, for that check
- * {@link Parcel#hasFileDescriptors()}
+ * @throws IllegalArgumentException if you provide any object not supported by above methods
+ * (including if the unsupported object is inside a nested container).
*
* @hide
*/
public static boolean hasFileDescriptors(Object value) {
- if (value instanceof LazyValue) {
- return ((LazyValue) value).hasFileDescriptors();
- } else if (value instanceof Parcelable) {
- if ((((Parcelable) value).describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ if (value instanceof Parcel) {
+ Parcel parcel = (Parcel) value;
+ if (parcel.hasFileDescriptors()) {
return true;
}
- } else if (value instanceof Parcelable[]) {
- Parcelable[] array = (Parcelable[]) value;
- for (int n = array.length - 1; n >= 0; n--) {
- Parcelable p = array[n];
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+ } else if (value instanceof LazyValue) {
+ LazyValue lazy = (LazyValue) value;
+ if (lazy.hasFileDescriptors()) {
+ return true;
+ }
+ } else if (value instanceof Parcelable) {
+ Parcelable parcelable = (Parcelable) value;
+ if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ return true;
+ }
+ } else if (value instanceof ArrayMap<?, ?>) {
+ ArrayMap<?, ?> map = (ArrayMap<?, ?>) value;
+ for (int i = 0, n = map.size(); i < n; i++) {
+ if (hasFileDescriptors(map.keyAt(i))
+ || hasFileDescriptors(map.valueAt(i))) {
+ return true;
+ }
+ }
+ } else if (value instanceof Map<?, ?>) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ if (hasFileDescriptors(entry.getKey())
+ || hasFileDescriptors(entry.getValue())) {
+ return true;
+ }
+ }
+ } else if (value instanceof List<?>) {
+ List<?> list = (List<?>) value;
+ for (int i = 0, n = list.size(); i < n; i++) {
+ if (hasFileDescriptors(list.get(i))) {
return true;
}
}
} else if (value instanceof SparseArray<?>) {
SparseArray<?> array = (SparseArray<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.valueAt(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && (p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
- return true;
- }
+ for (int i = 0, n = array.size(); i < n; i++) {
+ if (hasFileDescriptors(array.valueAt(i))) {
+ return true;
}
}
- } else if (value instanceof ArrayList<?>) {
- ArrayList<?> array = (ArrayList<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.get(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
- return true;
- }
+ } else if (value instanceof Object[]) {
+ Object[] array = (Object[]) value;
+ for (int i = 0, n = array.length; i < n; i++) {
+ if (hasFileDescriptors(array[i])) {
+ return true;
}
}
} else {
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 7b55e710..f4edcb1 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -156,10 +156,15 @@
}
/**
- * Constructs a PersistableBundle without initializing it.
+ * Constructs a {@link PersistableBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- PersistableBundle(boolean doInit) {
- super(doInit);
+ PersistableBundle(PersistableBundle from, boolean deep) {
+ super(from, deep);
}
/**
@@ -190,9 +195,7 @@
* are referenced as-is and not copied in any way.
*/
public PersistableBundle deepCopy() {
- PersistableBundle b = new PersistableBundle(false);
- b.copyInternal(this, true);
- return b;
+ return new PersistableBundle(this, /* deep */ true);
}
/**
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index a6316df..cde2063 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -17,10 +17,10 @@
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.content.ComponentName;
import android.content.Context;
import android.util.ArraySet;
import android.util.Log;
@@ -138,9 +138,9 @@
* @return The enabled component
* {@hide}
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- public List<String> getEnabledComponentOverrides(@NonNull String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) {
try {
return mInterface.getEnabledComponentOverrides(packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
new file mode 100644
index 0000000..cb521c8
--- /dev/null
+++ b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
@@ -0,0 +1,8 @@
+ewol@google.com
+hackbod@google.com
+jsharkey@google.com
+narayan@google.com
+patb@google.com
+svetoslavganov@google.com
+yamasani@google.com
+zhanghai@google.com
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index d39b56d..5b9d69c 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -191,20 +191,6 @@
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
- * Listen for changes of the network signal strengths (cellular) always reported from modem,
- * even in some situations such as the screen of the device is off.
- *
- * @see #onSignalStrengthsChanged
- *
- * @hide
- * @deprecated Use TelephonyManager#setSignalStrengthUpdateRequest
- * instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200;
-
- /**
* Listen for changes to observed cell info.
*
* Listening to this event requires the {@link Manifest.permission#READ_PHONE_STATE} and
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index bedad73..cb1cff9 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1041,10 +1041,6 @@
eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED);
}
- if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
- eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
- }
-
if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df69ed0..66fcf6c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2432,7 +2432,7 @@
<permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
android:protectionLevel="signature" />
- <!-- Allows listen permission to always reported signal strength.
+ <!-- Allows listen permission to always reported system signal strength.
@hide Used internally. -->
<permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
android:protectionLevel="signature" />
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 3045d7d5..c241e36 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -160,15 +160,27 @@
public void takeScreenshot(int displayId, RemoteCallback callback) {}
- public void setTouchExplorationPassthroughRegion(int displayId, Region region) {}
-
- public void setGestureDetectionPassthroughRegion(int displayId, Region region) {}
-
public void setFocusAppearance(int strokeWidth, int color) {}
public void logTrace(long timestamp, String where, String callingParams, int processId,
long threadId, int callingUid, Bundle callingStack) {}
+ public void setGestureDetectionPassthroughRegion(int displayId, Region region) {}
+
+ public void setTouchExplorationPassthroughRegion(int displayId, Region region) {}
+
+ public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {}
+
+ public void requestTouchExploration(int displayId) {}
+
+ public void requestDragging(int displayId, int pointerId) {}
+
+ public void requestDelegating(int displayId) {}
+
+ public void onDoubleTap(int displayId) {}
+
+ public void onDoubleTapAndHold(int displayId) {}
+
public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, Bundle serializedCallingStackInBundle) {}
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 73c2e8b..8e3d726 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -132,11 +132,12 @@
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"iconloader_base",
- "jsr330",
"protolog-lib",
"WindowManager-Shell-proto",
+ "dagger2",
"jsr330",
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
+ plugins: ["dagger2-compiler"],
}
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 9fe0247..7dc2f31 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -65,25 +65,28 @@
<LinearLayout
android:id="@+id/top_end_container"
android:layout_gravity="top|end"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
+
<ImageButton
android:id="@+id/settings"
android:layout_width="@dimen/pip_action_size"
android:layout_height="@dimen/pip_action_size"
android:contentDescription="@string/pip_phone_settings"
+ android:layout_gravity="top|start"
android:gravity="center"
android:src="@drawable/pip_ic_settings"
android:background="?android:selectableItemBackgroundBorderless" />
<ImageButton
- android:id="@+id/dismiss"
+ android:id="@+id/enter_split"
android:layout_width="@dimen/pip_action_size"
android:layout_height="@dimen/pip_action_size"
- android:contentDescription="@string/pip_phone_close"
+ android:layout_gravity="top|start"
android:gravity="center"
- android:src="@drawable/pip_ic_close_white"
+ android:contentDescription="@string/pip_phone_enter_split"
+ android:src="@drawable/pip_expand"
android:background="?android:selectableItemBackgroundBorderless" />
</LinearLayout>
@@ -97,4 +100,14 @@
android:padding="@dimen/pip_resize_handle_padding"
android:src="@drawable/pip_resize_handle"
android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageButton
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:contentDescription="@string/pip_phone_close"
+ android:layout_gravity="top|end"
+ android:gravity="center"
+ android:src="@drawable/pip_ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index d0e4f7a..0cdaa20 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -15,6 +15,10 @@
limitations under the License.
-->
<resources>
+ <!-- Determines whether the shell features all run on another thread. This is to be overrided
+ by the resources of the app using the Shell library. -->
+ <bool name="config_enableShellMainThread">false</bool>
+
<!-- Animation duration for PIP when entering. -->
<integer name="config_pipEnterAnimationDuration">425</integer>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 764854a..c88fc16 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -24,6 +24,9 @@
<!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
<string name="pip_phone_settings">Settings</string>
+ <!-- Label for the PIP enter split button [CHAR LIMIT=NONE] -->
+ <string name="pip_phone_enter_split">Enter split screen</string>
+
<!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
<string name="pip_menu_title">Menu</string>
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java
similarity index 71%
copy from packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java
copy to libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java
index 7292b9e..9ac7a12 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package com.android.wm.shell.common.annotations;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
-import javax.inject.Scope;
+import javax.inject.Qualifier;
/**
- * Scope annotation for singleton items within the WMComponent.
+ * Annotates a method or qualifies a provider that runs on the main-thread of the process using
+ * this library.
*/
+@Qualifier
@Documented
@Retention(RUNTIME)
-@Scope
-public @interface WMSingleton {
+public @interface ExternalMainThread {
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
new file mode 100644
index 0000000..1cd69ed
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
@@ -0,0 +1,13 @@
+The dagger modules in this directory can be included by the host SysUI using the Shell library for
+explicity injection of Shell components. Apps using this library are not required to use these
+dagger modules for setup, but it is recommended for them to include them as needed.
+
+The modules are currently inherited as such:
+
++- WMShellBaseModule (common shell features across SysUI)
+ |
+ +- WMShellModule (handheld)
+ |
+ +- TvPipModule (tv pip)
+ |
+ +- TvWMShellModule (tv)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index 3be1d3c..711a0ac 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.content.Context;
import android.os.Handler;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -44,6 +43,7 @@
import com.android.wm.shell.pip.tv.TvPipMenuController;
import com.android.wm.shell.pip.tv.TvPipNotificationController;
import com.android.wm.shell.pip.tv.TvPipTransition;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -161,13 +161,14 @@
PipTransitionController pipTransitionController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index dbdc460..6997d60 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.animation.AnimationHandler;
import android.content.Context;
import android.view.IWindowManager;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index b85ceefb..a564949 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -27,8 +27,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
index 61f50b5..5c205f9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
@@ -24,18 +24,18 @@
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Trace;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.R;
-import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
+import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.R;
import dagger.Module;
import dagger.Provides;
@@ -61,13 +61,26 @@
// Shell Concurrency - Components used for managing threading in the Shell and SysUI
//
+
+ /**
+ * Provide a SysUI main-thread Handler.
+ *
+ * Prefer the Main Executor when possible.
+ */
+ @Provides
+ @ExternalMainThread
+ public static Handler provideMainHandler() {
+ return new Handler(Looper.getMainLooper());
+ }
+
/**
* Provide a SysUI main-thread Executor.
*/
@WMSingleton
@Provides
- @Main
- public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
+ @ExternalMainThread
+ public static ShellExecutor provideSysUIMainExecutor(
+ @ExternalMainThread Handler sysuiMainHandler) {
return new HandlerExecutor(sysuiMainHandler);
}
@@ -78,7 +91,8 @@
@WMSingleton
@Provides
@ShellMainThread
- public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
+ public static Handler provideShellMainHandler(Context context,
+ @ExternalMainThread Handler sysuiMainHandler) {
if (enableShellMainThread(context)) {
HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY);
mainThread.start();
@@ -99,7 +113,8 @@
@Provides
@ShellMainThread
public static ShellExecutor provideShellMainExecutor(Context context,
- @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
+ @ShellMainThread Handler mainHandler,
+ @ExternalMainThread ShellExecutor sysuiMainExecutor) {
if (enableShellMainThread(context)) {
return new HandlerExecutor(mainHandler);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index a7c5ad2..ec70147 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.animation.AnimationHandler;
import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairsController;
@@ -57,6 +55,7 @@
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.Transitions;
@@ -217,14 +216,15 @@
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
PipTransitionController pipTransitionController,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java
index 7292b9e..7f45c38 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package com.android.wm.shell.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b6e5804..6cc5f09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -77,6 +77,7 @@
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -126,7 +127,8 @@
private final int mExitAnimationDuration;
private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Optional<LegacySplitScreenController> mSplitScreenOptional;
+ private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -252,7 +254,8 @@
@NonNull PipAnimationController pipAnimationController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@NonNull PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<LegacySplitScreenController> legacySplitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@@ -274,6 +277,7 @@
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
@@ -373,8 +377,11 @@
* activity render it's final configuration while the Task is still in PiP.
* - setWindowingMode to undefined at the end of transition
* @param animationDurationMs duration in millisecond for the exiting PiP transition
+ * @param requestEnterSplit whether the enterSplit button is pressed on PiP or not.
+ * Indicate the user wishes to directly put PiP into split screen
+ * mode.
*/
- public void exitPip(int animationDurationMs) {
+ public void exitPip(int animationDurationMs, boolean requestEnterSplit) {
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
|| mToken == null) {
@@ -387,7 +394,7 @@
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
- final int direction = syncWithSplitScreenBounds(destinationBounds)
+ final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
@@ -396,7 +403,7 @@
// We set to fullscreen here for now, but later it will be set to UNDEFINED for
// the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && !requestEnterSplit
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
@@ -435,7 +442,7 @@
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- mSplitScreenOptional.ifPresent(splitScreen -> {
+ mLegacySplitScreenOptional.ifPresent(splitScreen -> {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
}
@@ -1165,6 +1172,7 @@
@PipAnimationController.TransitionDirection int direction,
@PipAnimationController.AnimationType int type) {
final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
+ final boolean isPipTopLeft = isPipTopLeft();
mPipBoundsState.setBounds(destinationBounds);
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
@@ -1210,10 +1218,10 @@
null /* callback */, false /* withStartDelay */);
});
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
finishResizeForMenu(destinationBounds);
@@ -1241,7 +1249,11 @@
} else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen or split screen, then we need to reset the
// override bounds on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = null;
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ taskBounds = destinationBounds;
+ } else {
+ taskBounds = null;
+ }
applyWindowingModeChangeOnExit(wct, direction);
} else {
// Just a resize in PIP
@@ -1261,8 +1273,20 @@
* applying it.
*/
public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct,
- @PipAnimationController.TransitionDirection int direction) {
- mTaskOrganizer.applyTransaction(wct);
+ @PipAnimationController.TransitionDirection int direction, boolean wasPipTopLeft) {
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ mSplitScreenOptional.get().enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct);
+ } else {
+ mTaskOrganizer.applyTransaction(wct);
+ }
+ }
+
+ private boolean isPipTopLeft() {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+
+ return topLeft.contains(mPipBoundsState.getBounds());
}
/**
@@ -1347,18 +1371,27 @@
}
/**
- * Sync with {@link LegacySplitScreenController} on destination bounds if PiP is going to split
- * screen.
+ * Sync with {@link LegacySplitScreenController} or {@link SplitScreenController} on destination
+ * bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
- private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (!mSplitScreenOptional.isPresent()) {
+ private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
+ if (enterSplit && mSplitScreenOptional.isPresent()) {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+ final boolean isPipTopLeft = isPipTopLeft();
+ destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
+ return true;
+ }
+
+ if (!mLegacySplitScreenOptional.isPresent()) {
return false;
}
- LegacySplitScreenController legacySplitScreen = mSplitScreenOptional.get();
+ LegacySplitScreenController legacySplitScreen = mLegacySplitScreenOptional.get();
if (!legacySplitScreen.isDividerVisible()) {
// fail early if system is not in split screen mode
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index ae8c1b6..5687f4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -95,6 +95,11 @@
* Called when the PIP requested to show the menu.
*/
void onPipShowMenu();
+
+ /**
+ * Called when the PIP requested to enter Split.
+ */
+ void onEnterSplit();
}
private final Matrix mMoveTransform = new Matrix();
@@ -458,6 +463,10 @@
mListeners.forEach(Listener::onPipDismiss);
}
+ void onEnterSplit() {
+ mListeners.forEach(Listener::onEnterSplit);
+ }
+
/**
* @return the best set of actions to show in the PiP menu.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 47a8c67..69ae45d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -151,7 +151,7 @@
result = true;
break;
case AccessibilityNodeInfo.ACTION_EXPAND:
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
result = true;
break;
default:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 9d3baac..05f33b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -482,7 +482,8 @@
false /* fromShelfAdjustment */,
wct /* windowContainerTransaction */);
if (wct != null) {
- mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME);
+ mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME,
+ false /* wasPipTopLeft */);
}
};
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 3eeba6e..0644657 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.graphics.Rect;
-import android.util.Log;
-import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -34,6 +32,7 @@
protected ViewGroup mViewRoot;
protected ViewGroup mTopEndContainer;
protected View mDragHandle;
+ protected View mEnterSplitButton;
protected View mSettingsButton;
protected View mDismissButton;
@@ -44,14 +43,13 @@
* Bind the necessary views.
*/
public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
- View settingsButton, View dismissButton) {
+ View enterSplitButton, View settingsButton, View dismissButton) {
mViewRoot = viewRoot;
mTopEndContainer = topEndContainer;
mDragHandle = dragHandle;
+ mEnterSplitButton = enterSplitButton;
mSettingsButton = settingsButton;
mDismissButton = dismissButton;
-
- bindInitialViewState();
}
/**
@@ -72,22 +70,4 @@
v.setLayoutParams(params);
}
}
-
- /** Calculate the initial state of the menu icons. Called when the menu is first created. */
- private void bindInitialViewState() {
- if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
- || mSettingsButton == null || mDismissButton == null) {
- Log.e(TAG, "One of the required views is null.");
- return;
- }
- // The menu view layout starts out with the settings button aligned at the top|end of the
- // view group next to the dismiss button. On phones, the settings button should be aligned
- // to the top|start of the view, so move it to parent view group to then align it to the
- // top|start of the menu.
- mTopEndContainer.removeView(mSettingsButton);
- mViewRoot.addView(mSettingsButton);
-
- setLayoutGravity(mDragHandle, Gravity.START | Gravity.TOP);
- setLayoutGravity(mSettingsButton, Gravity.START | Gravity.TOP);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 8ef2b6b..7bbebe5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -99,7 +99,7 @@
private static final float MENU_BACKGROUND_ALPHA = 0.3f;
private static final float DISABLED_ACTION_ALPHA = 0.54f;
- private static final boolean ENABLE_RESIZE_HANDLE = false;
+ private static final boolean ENABLE_ENTER_SPLIT = false;
private int mMenuState;
private boolean mAllowMenuTimeout = true;
@@ -139,7 +139,7 @@
protected View mViewRoot;
protected View mSettingsButton;
protected View mDismissButton;
- protected View mResizeHandle;
+ protected View mEnterSplitButton;
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
@@ -177,14 +177,23 @@
}
});
- mResizeHandle = findViewById(R.id.resize_handle);
- mResizeHandle.setAlpha(0);
+ mEnterSplitButton = findViewById(R.id.enter_split);
+ mEnterSplitButton.setAlpha(0);
+ mEnterSplitButton.setOnClickListener(v -> {
+ if (mMenuContainer.getAlpha() != 0) {
+ enterSplit();
+ }
+ });
+
+ findViewById(R.id.resize_handle).setAlpha(0);
+
mActionsGroup = findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
- mResizeHandle, mSettingsButton, mDismissButton);
+ findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
+ mDismissButton);
mDismissFadeOutDurationMs = context.getResources()
.getInteger(R.integer.config_pipExitAnimationDuration);
@@ -268,14 +277,13 @@
mSettingsButton.getAlpha(), 1f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 1f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), ENABLE_ENTER_SPLIT ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- resizeAnim);
+ enterSplitAnim);
} else {
- mMenuContainerAnimator.playTogether(resizeAnim);
+ mMenuContainerAnimator.playTogether(enterSplitAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -328,7 +336,7 @@
mMenuContainer.setAlpha(0f);
mSettingsButton.setAlpha(0f);
mDismissButton.setAlpha(0f);
- mResizeHandle.setAlpha(0f);
+ mEnterSplitButton.setAlpha(0f);
}
void pokeMenu() {
@@ -368,9 +376,10 @@
mSettingsButton.getAlpha(), 0f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 0f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+ enterSplitAnim);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -522,6 +531,14 @@
}
}
+ private void enterSplit() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onEnterSplit, false /* notifyMenuVisibility */, true /* resize */,
+ ANIM_TYPE_HIDE);
+ }
+
+
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
PipUtils.getTopPipActivity(mContext);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index c42750d..96fd59f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -337,22 +337,29 @@
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* * fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip() {
- expandLeavePip(false /* skipAnimation */);
+ void expandLeavePip(boolean skipAnimation) {
+ expandLeavePip(skipAnimation, false /* enterSplit */);
+ }
+
+ /**
+ * Resizes the pinned task to split-screen mode.
+ */
+ void expandIntoSplit() {
+ expandLeavePip(false, true /* enterSplit */);
}
/**
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip(boolean skipAnimation) {
+ private void expandLeavePip(boolean skipAnimation, boolean enterSplit) {
if (DEBUG) {
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
- mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION);
+ mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION, enterSplit);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9f2f6a5..570fd5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -139,7 +139,12 @@
@Override
public void onPipExpand() {
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
+ }
+
+ @Override
+ public void onEnterSplit() {
+ mMotionHelper.expandIntoSplit();
}
@Override
@@ -899,7 +904,7 @@
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
setTouchEnabled(false);
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
}
} else if (mMenuState != MENU_STATE_FULL) {
if (mPipBoundsState.isStashed()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index a2e9b64..00083d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -219,7 +219,7 @@
public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
- mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
+ mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
onPipDisappeared();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 14a6574..dbd0ff8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -160,11 +160,25 @@
return moveToSideStage(task, sideStagePosition);
}
+ public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition,
+ WindowContainerTransaction wct) {
+ final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("Unknown taskId" + taskId);
+ }
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
}
+ public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
+ return mStageCoordinator.moveToSideStage(task, sideStagePosition, wct);
+ }
+
public boolean removeFromSideStage(int taskId) {
return mStageCoordinator.removeFromSideStage(taskId);
}
@@ -182,6 +196,11 @@
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
}
+ public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
+ moveToSideStage(taskId,
+ leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ }
+
public void exitSplitScreen(int toTopTaskId, int exitReason) {
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 3345613..a94a081 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -271,6 +271,11 @@
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
+ boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition, wct);
mSideStage.evictAllChildren(evictWct);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 0270093..0172cf32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -50,6 +50,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
@@ -75,7 +76,8 @@
@Mock private PipTransitionController mMockPipTransitionController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
- @Mock private Optional<LegacySplitScreenController> mMockOptionalSplitScreen;
+ @Mock private Optional<LegacySplitScreenController> mMockOptionalLegacySplitScreen;
+ @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
private TestShellExecutor mMainExecutor;
private PipBoundsState mPipBoundsState;
@@ -99,8 +101,9 @@
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
mPipBoundsAlgorithm, mMockPhonePipMenuController,
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
- mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
- mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
+ mMockPipTransitionController, mMockOptionalLegacySplitScreen,
+ mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger,
+ mMockShellTaskOrganizer, mMainExecutor));
mMainExecutor.flushAll();
preparePipTaskOrg();
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 50117ce..cae2d0b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2677,21 +2677,30 @@
// DENSITY_ANY is now dealt with. We should look to
// pick a density bucket and potentially scale it.
// Any density is potentially useful
- // because the system will scale it. Always prefer
- // scaling down.
+ // because the system will scale it. Scaling down
+ // is generally better than scaling up.
int h = thisDensity;
int l = otherDensity;
bool bImBigger = true;
if (l > h) {
- std::swap(l, h);
+ int t = h;
+ h = l;
+ l = t;
bImBigger = false;
}
+ if (requestedDensity >= h) {
+ // requested value higher than both l and h, give h
+ return bImBigger;
+ }
if (l >= requestedDensity) {
// requested value lower than both l and h, give l
return !bImBigger;
+ }
+ // saying that scaling down is 2x better than up
+ if (((2 * l) - requestedDensity) * h > requestedDensity * requestedDensity) {
+ return !bImBigger;
} else {
- // otherwise give h
return bImBigger;
}
}
diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp
index f5fd0f2..b54915f 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -27,19 +27,15 @@
static ResTable_config selectBest(const ResTable_config& target,
const Vector<ResTable_config>& configs) {
- Vector<ResTable_config> matchedConfigs;
+ ResTable_config bestConfig;
+ memset(&bestConfig, 0, sizeof(bestConfig));
const size_t configCount = configs.size();
for (size_t i = 0; i < configCount; i++) {
const ResTable_config& thisConfig = configs[i];
- if (thisConfig.match(target)) {
- matchedConfigs.add(thisConfig);
+ if (!thisConfig.match(target)) {
+ continue;
}
- }
- ResTable_config bestConfig = matchedConfigs[0];
- const size_t matchingConfigCount = matchedConfigs.size();
- for (size_t i = 1; i < matchingConfigCount; i++) {
- const ResTable_config& thisConfig = configs[i];
if (thisConfig.isBetterThan(bestConfig, &target)) {
bestConfig = thisConfig;
}
@@ -79,9 +75,6 @@
configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20));
ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
- configs.add(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1));
- ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
-
expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH);
configs.add(expectedBest);
ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2636ab2..8dcdc98 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -953,7 +953,7 @@
Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
android::content::AttributionSourceState attributionSource;
attributionSource.readFromParcel(parcel);
- sp<MediaPlayer> mp = new MediaPlayer(attributionSource);
+ sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource);
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index f0b59d8..1f10e5d 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout
+<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/split_shade_status_bar"
@@ -26,7 +26,8 @@
android:paddingLeft="@dimen/qs_panel_padding"
android:paddingRight="@dimen/qs_panel_padding"
android:visibility="gone"
- android:theme="@style/Theme.SystemUI.QuickSettings.Header">
+ android:theme="@style/Theme.SystemUI.QuickSettings.Header"
+ app:layoutDescription="@xml/combined_qs_header_scene">
<androidx.constraintlayout.widget.Guideline
android:layout_width="wrap_content"
@@ -39,76 +40,65 @@
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="0dp"
- app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
android:gravity="start|center_vertical"
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.QS.Status"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/date"
/>
<com.android.systemui.statusbar.policy.DateView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="0dp"
- app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
android:layout_gravity="start|center_vertical"
android:gravity="center_vertical"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.QS.Status"
app:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
- app:layout_constraintStart_toEndOf="@id/clock"
- app:layout_constraintEnd_toStartOf="@id/carrier_group"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="0"
/>
<include
android:id="@+id/carrier_group"
layout="@layout/qs_carrier_group"
+ app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ app:layout_constraintWidth_min="48dp"
android:layout_width="0dp"
android:layout_height="0dp"
- app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
app:layout_constrainedWidth="true"
android:layout_gravity="end|center_vertical"
android:layout_marginStart="8dp"
- android:focusable="false"
- android:minHeight="@dimen/split_shade_header_min_height"
- android:minWidth="48dp"
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="1"
/>
<com.android.systemui.statusbar.phone.StatusIconContainer
android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
android:paddingEnd="@dimen/signal_cluster_battery_padding"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
app:layout_constraintStart_toEndOf="@id/carrier_group"
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="1"
/>
<com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
- android:layout_height="0dp"
+ android:layout_height="48dp"
app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
app:textAppearance="@style/TextAppearance.QS.Status"
app:layout_constraintStart_toEndOf="@id/statusIcons"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
/>
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.motion.widget.MotionLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 5176d96..6f5d7be 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -18,7 +18,7 @@
-->
<!-- This is the status bar window. -->
-<com.android.systemui.statusbar.phone.StatusBarWindowView
+<com.android.systemui.statusbar.window.StatusBarWindowView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -35,4 +35,4 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/system_bar_background" />
-</com.android.systemui.statusbar.phone.StatusBarWindowView>
+</com.android.systemui.statusbar.window.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 96433e5..fc6b99a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -577,9 +577,6 @@
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">false</bool>
- <!-- Determines whether the shell features all run on another thread. -->
- <bool name="config_enableShellMainThread">false</bool>
-
<!-- Default udfps icon. Same path as ic_fingerprint.xml -->
<string name="config_udfpsIcon" translatable="false">
M25.5,16.3283C28.47,14.8433 31.9167,14 35.5834,14C39.2501,14 42.6968,14.8433 45.6668,16.3283
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
new file mode 100644
index 0000000..d61e4a9
--- /dev/null
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<MotionScene
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <Transition
+ android:id="@+id/header_transition"
+ app:constraintSetEnd="@id/qs_header_constraint"
+ app:constraintSetStart="@id/qqs_header_constraint">
+ <KeyFrameSet>
+ <KeyPosition
+ app:keyPositionType="pathRelative"
+ app:percentX="0"
+ app:framePosition="50"
+ app:motionTarget="@id/date" />
+ </KeyFrameSet>
+ </Transition>
+
+ <Transition
+ android:id="@+id/split_header_transition"
+ app:constraintSetStart="@id/split_header_constraint"
+ app:constraintSetEnd="@id/split_header_constraint"/>
+
+ <!--
+ Placeholder ConstraintSet. They are populated in the controller for this class.
+ This is needed because there's no easy way to just refer to a `ConstraintSet` file. The
+ options are either a layout file or inline the ConstraintSets.
+ -->
+ <ConstraintSet android:id="@id/qqs_header_constraint"/>
+
+ <ConstraintSet android:id="@id/qs_header_constraint"/>
+
+ <ConstraintSet android:id="@id/split_header_constraint" />
+
+</MotionScene>
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index fdf73d5..3d7b549 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -17,66 +17,45 @@
<ConstraintSet
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/qqs_header_constraint"
+>
<Constraint
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/date"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintHorizontal_chainStyle="packed"
- />
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/date"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/clock"
- app:layout_constraintEnd_toStartOf="@id/carrier_group"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="0"
- />
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toEndOf="@id/clock"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/carrier_group"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constrainedWidth="true"
- android:layout_gravity="end|center_vertical"
- android:layout_marginStart="8dp"
- app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- android:visibility="invisible"
- app:layout_constraintHorizontal_bias="1"
- />
+ android:id="@+id/carrier_group">
+ <CustomAttribute
+ app:attributeName="alpha"
+ app:customFloatValue="0"
+ />
+ </Constraint>
- <Constraint
- android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/carrier_group"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
- <Constraint
- android:id="@+id/batteryRemainingIcon"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index 72e518e..6a0ab86 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -17,63 +17,46 @@
<ConstraintSet
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/qs_header_constraint"
+>
<Constraint
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/date"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/carrier_group"
- app:layout_constraintHorizontal_bias="0"
- />
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/date"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/clock"
- app:layout_constraintHorizontal_bias="0"
- />
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/clock"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ <Motion
+ app:motionStagger="0.5"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/carrier_group"
- android:layout_width="0dp"
- android:layout_height="48dp"
- app:layout_constrainedWidth="true"
- android:layout_gravity="end|center_vertical"
- android:layout_marginStart="8dp"
- app:layout_constraintStart_toEndOf="@id/clock"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="@id/clock"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
+ android:id="@+id/carrier_group">
+ <CustomAttribute
+ app:attributeName="alpha"
+ app:customFloatValue="1"
+ />
+ </Constraint>
- <Constraint
- android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/carrier_group"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="@id/clock"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
-
- <Constraint
- android:id="@+id/batteryRemainingIcon"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="@id/clock"
- app:layout_constraintBottom_toBottomOf="parent"
- />
</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/split_header.xml b/packages/SystemUI/res/xml/split_header.xml
index a3ee1e2..44d42a0 100644
--- a/packages/SystemUI/res/xml/split_header.xml
+++ b/packages/SystemUI/res/xml/split_header.xml
@@ -17,61 +17,41 @@
<ConstraintSet
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/split_header_constraint">
<Constraint
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/date"
- />
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/date"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/clock"
- app:layout_constraintEnd_toStartOf="@id/carrier_group"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="0"
- />
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toEndOf="@id/clock"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
<Constraint
- android:id="@+id/carrier_group"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constrainedWidth="true"
- android:layout_gravity="end|center_vertical"
- android:layout_marginStart="8dp"
- app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
+ android:id="@+id/carrier_group">
+ <PropertySet
+ android:alpha="1"
+ app:customFloatValue="1"
+ />
+ </Constraint>
- <Constraint
- android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/carrier_group"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
-
- <Constraint
- android:id="@+id/batteryRemainingIcon"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 2f5a18e..7a39029 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -105,7 +105,6 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -129,6 +128,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
index b7398d8..dacc169 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
@@ -15,6 +15,8 @@
*/
package com.android.systemui.biometrics
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.PorterDuff
@@ -33,6 +35,8 @@
import android.view.LayoutInflater
import android.view.Surface
import android.view.View
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
import android.view.WindowManager
import androidx.annotation.RawRes
import com.airbnb.lottie.LottieAnimationView
@@ -42,6 +46,7 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
@@ -56,9 +61,10 @@
private val layoutInflater: LayoutInflater,
fingerprintManager: FingerprintManager?,
private val windowManager: WindowManager,
- @Main mainExecutor: DelayableExecutor,
+ overviewProxyService: OverviewProxyService,
displayManager: DisplayManager,
- @Main handler: Handler
+ @Main mainExecutor: DelayableExecutor,
+ @Main private val handler: Handler
) {
@VisibleForTesting
val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager
@@ -74,15 +80,33 @@
BiometricDisplayListener.SensorType.SideFingerprint(sensorProps)
) { onOrientationChanged() }
+ @VisibleForTesting
+ val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener {
+ override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) {
+ overlayView?.let { view ->
+ handler.postDelayed({ updateOverlayVisibility(view) }, 500)
+ }
+ }
+ }
+
+ private val animationDuration =
+ context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong()
+
+ private var overlayHideAnimator: ViewPropertyAnimator? = null
+
private var overlayView: View? = null
set(value) {
field?.let { oldView ->
windowManager.removeView(oldView)
orientationListener.disable()
}
+ overlayHideAnimator?.cancel()
+ overlayHideAnimator = null
+
field = value
field?.let { newView ->
windowManager.addView(newView, overlayViewParams)
+ updateOverlayVisibility(newView)
orientationListener.enable()
}
}
@@ -90,11 +114,8 @@
private val overlayViewParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
PixelFormat.TRANSLUCENT
).apply {
title = TAG
@@ -121,6 +142,7 @@
override fun hide(sensorId: Int) = mainExecutor.execute { overlayView = null }
})
+ overviewProxyService.addCallback(overviewProxyListener)
}
private fun onOrientationChanged() {
@@ -176,6 +198,33 @@
overlayViewParams.x = x
overlayViewParams.y = y
}
+
+ private fun updateOverlayVisibility(view: View) {
+ if (view != overlayView) {
+ return
+ }
+
+ // hide after a few seconds if the sensor is oriented down and there are
+ // large overlapping system bars
+ if ((context.display?.rotation == Surface.ROTATION_270) &&
+ windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar()) {
+ overlayHideAnimator = view.animate()
+ .alpha(0f)
+ .setStartDelay(3_000)
+ .setDuration(animationDuration)
+ .setListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ view.visibility = View.GONE
+ overlayHideAnimator = null
+ }
+ })
+ } else {
+ overlayHideAnimator?.cancel()
+ overlayHideAnimator = null
+ view.alpha = 1f
+ view.visibility = View.VISIBLE
+ }
+ }
}
@BiometricOverlayConstants.ShowReason
@@ -200,6 +249,9 @@
private fun Display.isPortrait(): Boolean =
rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+private fun WindowInsets.hasBigNavigationBar(): Boolean =
+ getInsets(WindowInsets.Type.navigationBars()).bottom >= 70
+
private fun LottieAnimationView.addOverlayDynamicColor(context: Context) {
fun update() {
val c = context.getColor(R.color.biometric_dialog_accent)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 778aff3..b484029 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -583,7 +583,7 @@
mCoreLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
- getCoreLayoutParamFlags(),
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
PixelFormat.TRANSLUCENT);
mCoreLayoutParams.setTitle(TAG);
mCoreLayoutParams.setFitInsetsTypes(0);
@@ -616,13 +616,6 @@
}
}
- private int getCoreLayoutParamFlags() {
- return WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
-
@Nullable
private FingerprintSensorPropertiesInternal findFirstUdfps() {
for (FingerprintSensorPropertiesInternal props :
@@ -685,7 +678,7 @@
final int paddingX = animation != null ? animation.getPaddingX() : 0;
final int paddingY = animation != null ? animation.getPaddingY() : 0;
- mCoreLayoutParams.flags = getCoreLayoutParamFlags();
+ mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS;
if (animation != null && animation.listenForTouchesOutsideView()) {
mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
index 322584c..6989547 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
@@ -31,6 +31,7 @@
import android.os.UserManager;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -46,6 +47,13 @@
public static final int CREDENTIAL_PATTERN = 2;
public static final int CREDENTIAL_PASSWORD = 3;
+ /** Base set of layout flags for fingerprint overlay widgets. */
+ public static final int FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD})
@interface CredentialType {}
@@ -55,11 +63,6 @@
/ DisplayMetrics.DENSITY_DEFAULT);
}
- static float pixelsToDp(Context context, float pixels) {
- return pixels / ((float) context.getResources().getDisplayMetrics().densityDpi
- / DisplayMetrics.DENSITY_DEFAULT);
- }
-
static void notifyAccessibilityContentChanged(AccessibilityManager am, ViewGroup view) {
if (!am.isEnabled()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4cecb39..dcb44cc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -73,6 +73,7 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
+import com.android.systemui.statusbar.window.StatusBarWindowModule;
import com.android.systemui.tuner.dagger.TunerModule;
import com.android.systemui.user.UserModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
@@ -116,6 +117,7 @@
SettingsUtilModule.class,
SmartRepliesInflationModule.class,
StatusBarPolicyModule.class,
+ StatusBarWindowModule.class,
SysUIConcurrencyModule.class,
TunerModule.class,
UserModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 634349e..d8b7742 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -20,13 +20,14 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.tv.TvWMComponent;
-import com.android.systemui.wmshell.TvWMShellModule;
-import com.android.systemui.wmshell.WMShellModule;
+import com.android.wm.shell.dagger.TvWMShellModule;
+import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 1343bdb..7770d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -44,6 +44,7 @@
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.VariableDateView;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import java.util.List;
@@ -312,6 +313,10 @@
}
private void updateAnimators() {
+ if (mUseCombinedQSHeader) {
+ mTranslationAnimator = null;
+ return;
+ }
updateAlphaAnimator();
int offset = mTopViewMeasureHeight;
@@ -324,6 +329,10 @@
}
private void updateAlphaAnimator() {
+ if (mUseCombinedQSHeader) {
+ mAlphaAnimator = null;
+ return;
+ }
TouchAnimator.Builder builder = new TouchAnimator.Builder()
.addFloat(mSecurityHeaderView, "alpha", 0, 1)
// These views appear on expanding down
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index bb697c3..74ea19f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -67,11 +67,13 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowModule;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 7e4db03..d5a0467 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -26,7 +26,7 @@
import android.widget.FrameLayout
import com.android.systemui.R
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
-import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index dcf8e73..5a27329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -31,8 +31,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.Assert
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index 80577ee..7cdf69d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -26,7 +26,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.InputChannelCompat
import com.android.systemui.shared.system.InputMonitorCompat
-import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index f068a8e..00b54e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -47,6 +47,7 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index fbe59a2..e66ad61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 09bcb69..0b3e040 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index e3d38b8..5305ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -37,6 +37,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.util.leak.RotationUtils;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index bac4234..c814622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -17,8 +17,7 @@
package com.android.systemui.statusbar.phone
import android.view.View
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.motion.widget.MotionLayout
import com.android.systemui.R
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
@@ -39,6 +38,11 @@
batteryMeterViewController: BatteryMeterViewController
) {
+ companion object {
+ private val HEADER_TRANSITION_ID = R.id.header_transition
+ private val SPLIT_HEADER_TRANSITION_ID = R.id.split_header_transition
+ }
+
private val combinedHeaders = featureFlags.useCombinedQSHeaders()
// TODO(b/194178072) Handle RSSI hiding when multi carrier
private val iconManager: StatusBarIconController.IconManager
@@ -59,6 +63,7 @@
}
field = value
updateVisibility()
+ updatePosition()
}
var splitShadeMode = false
@@ -68,6 +73,7 @@
}
field = value
updateVisibility()
+ updateConstraints()
}
var shadeExpandedFraction = -1f
@@ -83,13 +89,22 @@
if (visible && field != value) {
field = value
updateVisibility()
+ updatePosition()
}
}
- private val constraintSplit = ConstraintSet()
- .apply { load(statusBar.context, R.xml.split_header) }
- private val constraintQQS = ConstraintSet().apply { load(statusBar.context, R.xml.qqs_header) }
- private val constraintQS = ConstraintSet().apply { load(statusBar.context, R.xml.qs_header) }
+ init {
+ if (statusBar is MotionLayout) {
+ val context = statusBar.context
+ val resources = statusBar.resources
+ statusBar.getConstraintSet(R.id.qqs_header_constraint)
+ .load(context, resources.getXml(R.xml.qqs_header))
+ statusBar.getConstraintSet(R.id.qs_header_constraint)
+ .load(context, resources.getXml(R.xml.qs_header))
+ statusBar.getConstraintSet(R.id.split_header_constraint)
+ .load(context, resources.getXml(R.xml.split_header))
+ }
+ }
init {
batteryMeterViewController.init()
@@ -104,6 +119,8 @@
qsCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(statusBar.findViewById(R.id.carrier_group))
.build()
+ updateVisibility()
+ updateConstraints()
}
private fun updateVisibility() {
@@ -118,20 +135,25 @@
statusBar.visibility = visibility
visible = visibility == View.VISIBLE
}
- updateConstraints()
}
private fun updateConstraints() {
if (!combinedHeaders) {
return
}
- statusBar as ConstraintLayout
+ statusBar as MotionLayout
if (splitShadeMode) {
- constraintSplit.applyTo(statusBar)
- } else if (qsExpandedFraction == 1f) {
- constraintQS.applyTo(statusBar)
+ statusBar.setTransition(SPLIT_HEADER_TRANSITION_ID)
} else {
- constraintQQS.applyTo(statusBar)
+ statusBar.setTransition(HEADER_TRANSITION_ID)
+ statusBar.transitionToStart()
+ updatePosition()
+ }
+ }
+
+ private fun updatePosition() {
+ if (statusBar is MotionLayout && !splitShadeMode && visible) {
+ statusBar.setProgress(qsExpandedFraction)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 0f0810d..315ef77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -229,6 +229,8 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
@@ -467,7 +469,7 @@
private AuthRippleController mAuthRippleController;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected NotificationShadeWindowController mNotificationShadeWindowController;
- protected StatusBarWindowController mStatusBarWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@VisibleForTesting
DozeServiceHost mDozeServiceHost;
@@ -701,6 +703,7 @@
NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
+ StatusBarWindowController statusBarWindowController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
@@ -802,6 +805,7 @@
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
+ mStatusBarWindowController = statusBarWindowController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mPulseExpansionHandler = pulseExpansionHandler;
mWakeUpCoordinator = notificationWakeUpCoordinator;
@@ -1588,7 +1592,6 @@
.getNotificationShadeWindowViewController();
mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
- mStatusBarWindowController = statusBarComponent.getStatusBarWindowController();
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
statusBarComponent.getLockIconViewController().init();
mStackScrollerController = statusBarComponent.getNotificationStackScrollLayoutController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index ca877af..6eeae7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index 418f588..e06605e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -29,7 +29,6 @@
import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks;
import com.android.systemui.statusbar.phone.StatusBarDemoMode;
import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -82,12 +81,6 @@
NotificationShadeWindowViewController getNotificationShadeWindowViewController();
/**
- * Creates a StatusBarWindowViewController.
- */
- @StatusBarScope
- StatusBarWindowController getStatusBarWindowController();
-
- /**
* Creates a NotificationPanelViewController.
*/
@StatusBarScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 4f43426..8f57faa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -108,6 +108,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
@@ -146,6 +147,7 @@
NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
+ StatusBarWindowController statusBarWindowController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
@@ -249,6 +251,7 @@
notificationsController,
lightBarController,
autoHideController,
+ statusBarWindowController,
keyguardUpdateMonitor,
pulseExpansionHandler,
notificationWakeUpCoordinator,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 31cc823..1225813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -39,8 +39,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
-import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index b26aab86..700b58a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.window;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
@@ -34,7 +34,6 @@
import android.util.Log;
import android.view.Gravity;
import android.view.IWindowManager;
-import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
@@ -47,6 +46,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import java.util.Optional;
@@ -78,6 +78,7 @@
@Inject
public StatusBarWindowController(
Context context,
+ @StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
WindowManager windowManager,
IWindowManager iWindowManager,
StatusBarContentInsetsProvider contentInsetsProvider,
@@ -86,7 +87,7 @@
mWindowManager = windowManager;
mIWindowManager = iWindowManager;
mContentInsetsProvider = contentInsetsProvider;
- mStatusBarWindowView = createWindowView(mContext);
+ mStatusBarWindowView = statusBarWindowView;
mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
R.id.status_bar_launch_animation_container);
mLpChanged = new WindowManager.LayoutParams();
@@ -294,14 +295,4 @@
mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
}
}
-
- private ViewGroup createWindowView(Context context) {
- ViewGroup view = (ViewGroup) LayoutInflater.from(context).inflate(
- R.layout.super_status_bar, /* root= */ null);
- if (view == null) {
- throw new IllegalStateException(
- "R.layout.super_status_bar could not be properly inflated");
- }
- return view;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
new file mode 100644
index 0000000..874217a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
@@ -0,0 +1,47 @@
+package com.android.systemui.statusbar.window
+
+import android.view.LayoutInflater
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+import javax.inject.Qualifier
+
+/** Module providing dependencies related to the status bar window. */
+@Module
+abstract class StatusBarWindowModule {
+ /**
+ * Provides a [StatusBarWindowView].
+ *
+ * Only [StatusBarWindowController] should inject the view.
+ */
+ @Module
+ companion object {
+ @JvmStatic
+ @Provides
+ @SysUISingleton
+ @InternalWindowView
+ fun providesStatusBarWindowView(layoutInflater: LayoutInflater): StatusBarWindowView {
+ return layoutInflater.inflate(
+ R.layout.super_status_bar,
+ /* root= */null
+ ) as StatusBarWindowView?
+ ?: throw IllegalStateException(
+ "R.layout.super_status_bar could not be properly inflated"
+ )
+ }
+ }
+
+ /**
+ * We want [StatusBarWindowView] to be provided to [StatusBarWindowController]'s constructor via
+ * dagger so that we can provide a fake window view when testing the controller. However, we wan
+ * want *only* the controller to be able to inject the window view.
+ *
+ * This protected qualifier annotation achieves this. [StatusBarWindowView] can only be injected
+ * if it's annotated with [InternalWindowView], and only classes inside this [statusbar.window]
+ * package can access the annotation.
+ */
+ @Retention(AnnotationRetention.BINARY)
+ @Qualifier
+ protected annotation class InternalWindowView
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
index eb8c7ad..06cc96e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.window;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
@@ -36,7 +36,7 @@
public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "PhoneStatusBarWindowView";
- public static final boolean DEBUG = StatusBar.DEBUG;
+ public static final boolean DEBUG = false;
private int mLeftInset = 0;
private int mRightInset = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
index f678513..8370615 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
@@ -17,8 +17,8 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.wmshell.TvWMShellModule;
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.dagger.TvWMShellModule;
import dagger.Subcomponent;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
index 5fee7fb..c98a504 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics
+import android.animation.Animator
+import android.graphics.Insets
import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
@@ -33,7 +35,9 @@
import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
import android.view.DisplayInfo
import android.view.LayoutInflater
+import android.view.Surface
import android.view.View
+import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowMetrics
@@ -41,6 +45,7 @@
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
@@ -53,6 +58,8 @@
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.anyLong
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -81,6 +88,8 @@
@Mock
lateinit var displayManager: DisplayManager
@Mock
+ lateinit var overviewProxyService: OverviewProxyService
+ @Mock
lateinit var handler: Handler
@Captor
lateinit var overlayCaptor: ArgumentCaptor<View>
@@ -91,45 +100,62 @@
@Before
fun setup() {
+ context.addMockSystemService(DisplayManager::class.java, displayManager)
+ context.addMockSystemService(WindowManager::class.java, windowManager)
+
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView)
`when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
.thenReturn(mock(LottieAnimationView::class.java))
+ with(mock(ViewPropertyAnimator::class.java)) {
+ `when`(sidefpsView.animate()).thenReturn(this)
+ `when`(alpha(anyFloat())).thenReturn(this)
+ `when`(setStartDelay(anyLong())).thenReturn(this)
+ `when`(setDuration(anyLong())).thenReturn(this)
+ `when`(setListener(any())).thenAnswer {
+ (it.arguments[0] as Animator.AnimatorListener)
+ .onAnimationEnd(mock(Animator::class.java))
+ this
+ }
+ }
`when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
- listOf(
- FingerprintSensorPropertiesInternal(
- SENSOR_ID,
- SensorProperties.STRENGTH_STRONG,
- 5 /* maxEnrollmentsPerUser */,
- listOf() /* componentInfo */,
- FingerprintSensorProperties.TYPE_POWER_BUTTON,
- true /* resetLockoutRequiresHardwareAuthToken */
- )
+ listOf(
+ FingerprintSensorPropertiesInternal(
+ SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ listOf() /* componentInfo */,
+ FingerprintSensorProperties.TYPE_POWER_BUTTON,
+ true /* resetLockoutRequiresHardwareAuthToken */
)
- )
- `when`(windowManager.defaultDisplay).thenReturn(
- Display(
- DisplayManagerGlobal.getInstance(),
- DISPLAY_ID,
- DisplayInfo(),
- DEFAULT_DISPLAY_ADJUSTMENTS
- )
+ )
)
`when`(windowManager.maximumWindowMetrics).thenReturn(
WindowMetrics(Rect(0, 0, 800, 800), WindowInsets.CONSUMED)
)
+ }
+
+ private fun testWithDisplay(initInfo: DisplayInfo.() -> Unit = {}, block: () -> Unit) {
+ val displayInfo = DisplayInfo()
+ displayInfo.initInfo()
+ val dmGlobal = mock(DisplayManagerGlobal::class.java)
+ val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS)
+ `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo)
+ `when`(windowManager.defaultDisplay).thenReturn(display)
sideFpsController = SidefpsController(
- mContext, layoutInflater, fingerprintManager, windowManager, executor,
- displayManager, handler
+ context.createDisplayContext(display), layoutInflater, fingerprintManager,
+ windowManager, overviewProxyService, displayManager, executor, handler
)
overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply {
verify(fingerprintManager).setSidefpsController(capture())
}.value
+
+ block()
}
@Test
- fun testSubscribesToOrientationChangesWhenShowingOverlay() {
+ fun testSubscribesToOrientationChangesWhenShowingOverlay() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -141,7 +167,7 @@
}
@Test
- fun testShowsAndHides() {
+ fun testShowsAndHides() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -156,7 +182,7 @@
}
@Test
- fun testShowsOnce() {
+ fun testShowsOnce() = testWithDisplay {
repeat(5) {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -167,7 +193,7 @@
}
@Test
- fun testHidesOnce() {
+ fun testHidesOnce() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -181,10 +207,64 @@
}
@Test
- fun testIgnoredForKeyguard() {
- overlayController.show(SENSOR_ID, REASON_AUTH_KEYGUARD)
+ fun testIgnoredForKeyguard() = testWithDisplay {
+ testIgnoredFor(REASON_AUTH_KEYGUARD)
+ }
+
+ private fun testIgnoredFor(reason: Int) {
+ overlayController.show(SENSOR_ID, reason)
+
executor.runAllReady()
verify(windowManager, never()).addView(any(), any())
}
+
+ @Test
+ fun showsWithTaskbar() = testWithDisplay({ rotation = Surface.ROTATION_0 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbar90() = testWithDisplay({ rotation = Surface.ROTATION_90 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbar180() = testWithDisplay({ rotation = Surface.ROTATION_180 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbarCollapsedDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) {
+ `when`(windowManager.currentWindowMetrics).thenReturn(
+ WindowMetrics(Rect(0, 0, 800, 800), insetsForSmallNavbar())
+ )
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun hidesWithTaskbarDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) {
+ `when`(windowManager.currentWindowMetrics).thenReturn(
+ WindowMetrics(Rect(0, 0, 800, 800), insetsForLargeNavbar())
+ )
+ hidesWithTaskbar(visible = false)
+ }
+
+ private fun hidesWithTaskbar(visible: Boolean) {
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false)
+ executor.runAllReady()
+
+ verify(windowManager).addView(any(), any())
+ verify(windowManager, never()).removeView(any())
+ verify(sidefpsView).visibility = if (visible) View.VISIBLE else View.GONE
+ }
}
+
+private fun insetsForSmallNavbar() = insetsWithBottom(60)
+private fun insetsForLargeNavbar() = insetsWithBottom(100)
+private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder()
+ .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom))
+ .build()
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 25aa93a..bd4efdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 4bf8821..1adba6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -54,6 +54,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 9202cec..e2bd62a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -141,6 +141,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
@@ -224,6 +225,7 @@
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private DynamicPrivacyController mDynamicPrivacyController;
@Mock private AutoHideController mAutoHideController;
+ @Mock private StatusBarWindowController mStatusBarWindowController;
@Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
@Mock private UserSwitcherController mUserSwitcherController;
@Mock private NetworkController mNetworkController;
@@ -366,6 +368,7 @@
mNotificationsController,
mLightBarController,
mAutoHideController,
+ mStatusBarWindowController,
mKeyguardUpdateMonitor,
mPulseExpansionHandler,
mNotificationWakeUpCoordinator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 3d2ff47..b385b7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -42,7 +42,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
-import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp
new file mode 100644
index 0000000..9a6fa8e
--- /dev/null
+++ b/rs/jni/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+ name: "librs_jni",
+
+ srcs: ["android_renderscript_RenderScript.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "libandroid_runtime",
+ "libandroidfw",
+ "libRS",
+ "libcutils",
+ "libhwui",
+ "liblog",
+ "libutils",
+ "libui",
+ "libgui",
+ "libjnigraphics",
+ ],
+
+ header_libs: [
+ "jni_headers",
+ "libbase_headers",
+ ],
+
+ include_dirs: ["frameworks/rs"],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wunused",
+ "-Wunreachable-code",
+ "-Wno-deprecated-declarations",
+ ],
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
deleted file mode 100644
index 0caba42..0000000
--- a/rs/jni/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_renderscript_RenderScript.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid \
- libandroid_runtime \
- libandroidfw \
- libRS \
- libcutils \
- libhwui \
- liblog \
- libutils \
- libui \
- libgui \
- libjnigraphics
-
-LOCAL_HEADER_LIBRARIES := \
- jni_headers \
- libbase_headers
-
-LOCAL_C_INCLUDES += \
- frameworks/rs
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations
-
-LOCAL_MODULE:= librs_jni
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index acdbcb58..67bb726 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -256,6 +256,18 @@
void setGestureDetectionPassthroughRegion(int displayId, Region region);
void setTouchExplorationPassthroughRegion(int displayId, Region region);
+
+ void setServiceDetectsGesturesEnabled(int displayId, boolean mode);
+
+ void requestTouchExploration(int displayId);
+
+ void requestDragging(int displayId, int pointerId);
+
+ void requestDelegating(int displayId);
+
+ void onDoubleTap(int displayId);
+
+ void onDoubleTapAndHold(int displayId);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -1650,7 +1662,7 @@
}
}
- private IAccessibilityServiceClient getServiceInterfaceSafely() {
+ protected IAccessibilityServiceClient getServiceInterfaceSafely() {
synchronized (mLock) {
return mServiceInterface;
}
@@ -2048,4 +2060,28 @@
protected void logTraceWM(String methodName, String params) {
mTrace.logTrace(TRACE_WM + "." + methodName, FLAGS_WINDOW_MANAGER_INTERNAL, params);
}
+
+ public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
+ mSystemSupport.setServiceDetectsGesturesEnabled(displayId, mode);
+ }
+
+ public void requestTouchExploration(int displayId) {
+ mSystemSupport.requestTouchExploration(displayId);
+ }
+
+ public void requestDragging(int displayId, int pointerId) {
+ mSystemSupport.requestDragging(displayId, pointerId);
+ }
+
+ public void requestDelegating(int displayId) {
+ mSystemSupport.requestDelegating(displayId);
+ }
+
+ public void onDoubleTap(int displayId) {
+ mSystemSupport.onDoubleTap(displayId);
+ }
+
+ public void onDoubleTapAndHold(int displayId) {
+ mSystemSupport.onDoubleTapAndHold(displayId);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 10cfd04..75724bf 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -893,6 +893,42 @@
}
}
+ public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).setServiceDetectsGestures(mode);
+ }
+ }
+
+ public void requestTouchExploration(int displayId) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).requestTouchExploration();
+ }
+ }
+
+ public void requestDragging(int displayId, int pointerId) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).requestDragging(pointerId);
+ }
+ }
+
+ public void requestDelegating(int displayId) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).requestDelegating();
+ }
+ }
+
+ public void onDoubleTap(int displayId) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).onDoubleTap();
+ }
+ }
+
+ public void onDoubleTapAndHold(int displayId) {
+ if (mTouchExplorer.contains(displayId)) {
+ mTouchExplorer.get(displayId).onDoubleTapAndHold();
+ }
+ }
+
/**
* Dumps all {@link AccessibilityInputFilter}s here.
*/
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e6f91a25f..214769b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -44,6 +44,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.TouchInteractionController;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -101,6 +102,7 @@
import android.view.IWindow;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
+import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
@@ -1198,7 +1200,7 @@
}
/**
- * Called when a gesture is detected on a display.
+ * Called when a gesture is detected on a display by the framework.
*
* @param gestureEvent the detail of the gesture.
* @return true if the event is handled.
@@ -1213,6 +1215,29 @@
}
}
+ /** Send a motion event to the service to allow it to perform gesture detection. */
+ public boolean sendMotionEventToListeningServices(MotionEvent event) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Sending event to service: " + event);
+ }
+ return notifyMotionEvent(event);
+ }
+ }
+
+ /**
+ * Notifies services that the touch state on a given display has changed.
+ */
+ public boolean onTouchStateChanged(int displayId, int state) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Notifying touch state:"
+ + TouchInteractionController.stateToString(state));
+ }
+ return notifyTouchState(displayId, state);
+ }
+ }
+
/**
* Called when the system action list is changed.
*/
@@ -1527,6 +1552,30 @@
return false;
}
+ private boolean notifyMotionEvent(MotionEvent event) {
+ AccessibilityUserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ AccessibilityServiceConnection service = state.mBoundServices.get(i);
+ if (service.mRequestTouchExplorationMode) {
+ service.notifyMotionEvent(event);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean notifyTouchState(int displayId, int touchState) {
+ AccessibilityUserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ AccessibilityServiceConnection service = state.mBoundServices.get(i);
+ if (service.mRequestTouchExplorationMode) {
+ service.notifyTouchState(displayId, touchState);
+ return true;
+ }
+ }
+ return false;
+ }
+
private void notifyClearAccessibilityCacheLocked() {
AccessibilityUserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
@@ -2083,7 +2132,6 @@
if (userState.isSendMotionEventsEnabled()) {
flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS;
}
-
if (userState.isAutoclickEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
}
@@ -3960,6 +4008,93 @@
}
}
+ @Override
+ public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
+ mMainHandler.sendMessage(
+ obtainMessage(AccessibilityManagerService::setServiceDetectsGesturesInternal, this,
+ displayId, mode));
+ }
+
+ private void setServiceDetectsGesturesInternal(int displayId, boolean mode) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode);
+ }
+ }
+ }
+
+ @Override
+ public void requestTouchExploration(int displayId) {
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::requestTouchExplorationInternal, this, displayId));
+ }
+
+ private void requestTouchExplorationInternal(int displayId) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.requestTouchExploration(displayId);
+ }
+ }
+ }
+
+ @Override
+ public void requestDragging(int displayId, int pointerId) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::requestDraggingInternal,
+ this, displayId, pointerId));
+ }
+
+ private void requestDraggingInternal(int displayId, int pointerId) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.requestDragging(displayId, pointerId);
+ }
+ }
+ }
+
+ @Override
+ public void requestDelegating(int displayId) {
+ mMainHandler.sendMessage(
+ obtainMessage(
+ AccessibilityManagerService::requestDelegatingInternal, this, displayId));
+ }
+
+ private void requestDelegatingInternal(int displayId) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.requestDelegating(displayId);
+ }
+ }
+ }
+
+ @Override
+ public void onDoubleTap(int displayId) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapInternal,
+ this, displayId));
+ }
+
+ private void onDoubleTapInternal(int displayId) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.onDoubleTap(displayId);
+ }
+ }
+ }
+
+ @Override
+ public void onDoubleTapAndHold(int displayId) {
+ mMainHandler
+ .sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapAndHoldInternal,
+ this, displayId));
+ }
+
+ private void onDoubleTapAndHoldInternal(int displayId) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.onDoubleTapAndHold(displayId);
+ }
+ }
+ }
+
private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) {
if (userState.mUserId != mCurrentUserId) {
return;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 4bf48a2..e9f5870 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -22,6 +22,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityTrace;
import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.TouchInteractionController;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -30,12 +31,15 @@
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.view.Display;
+import android.view.MotionEvent;
+
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -454,4 +458,48 @@
mSystemSupport.onClientChangeLocked(false);
}
}
+
+ public void notifyMotionEvent(MotionEvent event) {
+ final Message msg = obtainMessage(
+ AccessibilityServiceConnection::notifyMotionEventInternal,
+ AccessibilityServiceConnection.this, event);
+ mMainHandler.sendMessage(msg);
+ }
+
+ public void notifyTouchState(int displayId, int state) {
+ final Message msg = obtainMessage(
+ AccessibilityServiceConnection::notifyTouchStateInternal,
+ AccessibilityServiceConnection.this, displayId, state);
+ mMainHandler.sendMessage(msg);
+ }
+
+ private void notifyMotionEventInternal(MotionEvent event) {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (mTrace.isA11yTracingEnabled()) {
+ logTraceSvcClient(".onMotionEvent ",
+ event.toString());
+ }
+ listener.onMotionEvent(event);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
+ }
+ }
+ }
+
+ private void notifyTouchStateInternal(int displayId, int state) {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (mTrace.isA11yTracingEnabled()) {
+ logTraceSvcClient(".onTouchStateChanged ",
+ TouchInteractionController.stateToString(state));
+ }
+ listener.onTouchStateChanged(displayId, state);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
+ }
+ }
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index df4a52e..b6223c7 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -382,18 +382,21 @@
}
public boolean longPressWithTouchEvents(MotionEvent event, int policyFlags) {
- final int pointerIndex = event.getActionIndex();
- final int pointerId = event.getPointerId(pointerIndex);
Point clickLocation = mTempPoint;
final int result = computeClickLocation(clickLocation);
if (result == CLICK_LOCATION_NONE) {
return false;
}
- mLongPressingPointerId = pointerId;
- mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
- mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;
- sendDownForAllNotInjectedPointers(event, policyFlags);
- return true;
+ if (event != null) {
+ final int pointerIndex = event.getActionIndex();
+ final int pointerId = event.getPointerId(pointerIndex);
+ mLongPressingPointerId = pointerId;
+ mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
+ mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;
+ sendDownForAllNotInjectedPointers(event, policyFlags);
+ return true;
+ }
+ return false;
}
void clear() {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 74f0bcb..946d22e4 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -46,6 +46,7 @@
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.view.Display;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -152,6 +153,7 @@
private Region mGestureDetectionPassthroughRegion;
private Region mTouchExplorationPassthroughRegion;
+ private int mDisplayId = Display.INVALID_DISPLAY;
/**
* Creates a new instance.
@@ -182,8 +184,9 @@
TouchExplorer(Context context, AccessibilityManagerService service, GestureManifold detector,
@NonNull Handler mainHandler) {
mContext = context;
+ mDisplayId = context.getDisplayId();
mAms = service;
- mState = new TouchState();
+ mState = new TouchState(mDisplayId, mAms);
mReceivedPointerTracker = mState.getReceivedPointerTracker();
mDispatcher = new EventDispatcher(context, mAms, super.getNext(), mState);
mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
@@ -267,6 +270,7 @@
}
try {
checkForMalformedEvent(event);
+ checkForMalformedEvent(rawEvent);
} catch (IllegalArgumentException e) {
Slog.e(LOG_TAG, "Ignoring malformed event: " + event.toString(), e);
return;
@@ -277,7 +281,7 @@
Slog.d(LOG_TAG, mState.toString());
}
- mState.onReceivedMotionEvent(rawEvent);
+ mState.onReceivedMotionEvent(event, rawEvent, policyFlags);
if (shouldPerformGestureDetection(event)) {
if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) {
// Event was handled by the gesture detector.
@@ -307,9 +311,12 @@
// It will be delivered on gesture completion or cancelation.
// Note that the delay for sending GESTURE_DETECTION_END remains in place.
mSendTouchInteractionEndDelayed.cancel();
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ }
} else {
Slog.e(LOG_TAG, "Illegal state: " + mState);
- clear(event, policyFlags);
+ clear(event, policyFlags);
}
}
@@ -367,7 +374,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -389,7 +396,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_DOUBLE_TAP,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -404,13 +411,37 @@
if (!mAms.performActionOnAccessibilityFocusedItem(
AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)) {
Slog.e(LOG_TAG, "ACTION_CLICK failed. Dispatching motion events to simulate click.");
-
- mDispatcher.clickWithTouchEvents(event, rawEvent, policyFlags);
+ if (event != null && rawEvent != null) {
+ mDispatcher.clickWithTouchEvents(event, rawEvent, policyFlags);
+ }
return true;
}
return true;
}
+ /**
+ * Executes a double-tap. The framework will first attempt to execute the appropriate
+ * accessibility action and if that fails, the framework will deliver touch events to the last
+ * touch-explored location.
+ */
+ public void onDoubleTap() {
+ MotionEvent event = mState.getLastReceivedEvent();
+ MotionEvent rawEvent = mState.getLastReceivedRawEvent();
+ int policyFlags = mState.getLastReceivedPolicyFlags();
+ onDoubleTap(event, rawEvent, policyFlags);
+ }
+
+ /**
+ * Executes a double-tap and hold gesture using touch events. The user can continue to move
+ * their finger around the screen to execute a drag.
+ */
+ public void onDoubleTapAndHold() {
+ MotionEvent event = mState.getLastReceivedEvent();
+ MotionEvent rawEvent = mState.getLastReceivedRawEvent();
+ int policyFlags = mState.getLastReceivedPolicyFlags();
+ onDoubleTapAndHold(event, rawEvent, policyFlags);
+ }
+
@Override
public boolean onGestureStarted() {
if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
@@ -473,7 +504,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_UNKNOWN,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -502,7 +533,6 @@
*/
private void handleActionDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
mAms.onTouchInteractionStart();
-
// If we still have not notified the user for the last
// touch, we figure out what to do. If were waiting
// we resent the delayed callback and wait again.
@@ -512,7 +542,6 @@
if (mState.isTouchExploring()) {
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
-
if (mState.isClear()) {
if (!mSendHoverEnterAndMoveDelayed.isPending()) {
// Queue a delayed transition to STATE_TOUCH_EXPLORING.
@@ -521,7 +550,14 @@
// The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
- mSendHoverEnterAndMoveDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
+ if (mState.isServiceDetectingGestures()) {
+ // This transition will be triggered manually by the service.
+ mSendHoverEnterAndMoveDelayed.setPointerIdBits(pointerIdBits);
+ mSendHoverEnterAndMoveDelayed.setPolicyFlags(policyFlags);
+ mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
+ } else {
+ mSendHoverEnterAndMoveDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
+ }
} else {
// Cache the event until we discern exploration from gesturing.
mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
@@ -548,6 +584,9 @@
// Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double tap.
mSendTouchInteractionEndDelayed.cancel();
}
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ }
}
/**
@@ -571,6 +610,11 @@
case ACTION_MOVE:
handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
break;
+ case ACTION_POINTER_UP:
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ }
+ break;
case ACTION_UP:
handleActionUp(event, rawEvent, policyFlags);
break;
@@ -612,15 +656,16 @@
// Another finger down means that if we have not started to deliver
// hover events, we will not have to. The code for ACTION_MOVE will
// decide what we will actually do next.
-
if (mSendHoverEnterAndMoveDelayed.isPending()) {
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
} else {
- // We have already delivered at least one hover event, so send hover exit to keep the
- // stream consistent.
+ // We have already delivered at least one hover event, so send hover exit to keep
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ }
}
/**
@@ -632,12 +677,19 @@
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIndex = event.findPointerIndex(pointerId);
int pointerIdBits = (1 << pointerId);
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
+ return;
+ }
switch (event.getPointerCount()) {
case 1:
// We have not started sending events since we try to
// figure out what the user is doing.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// Cache the event until we discern exploration from gesturing.
+ // When the service is detecting gestures we rely on it to fire touch
+ // exploration.
mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
}
break;
@@ -684,7 +736,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -708,7 +760,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -730,7 +782,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -751,7 +803,7 @@
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
- event.getDisplayId(),
+ mDisplayId,
mGestureDetector.getMotionEvents());
dispatchGesture(gestureEvent);
}
@@ -767,7 +819,10 @@
* Handles ACTION_UP while in the touch interacting state. This event represents all fingers
* being lifted from the screen.
*/
- private void handleActionUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ private void handleActionUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (mState.isServiceDetectingGestures() && mState.isTouchInteracting()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ }
mAms.onTouchInteractionEnd();
final int pointerId = event.getPointerId(event.getActionIndex());
final int pointerIdBits = (1 << pointerId);
@@ -883,6 +938,10 @@
clear(event, policyFlags);
return;
case ACTION_POINTER_DOWN:
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ return;
+ }
// We are in dragging state so we have two pointers and another one
// goes down => delegate the three pointers to the view hierarchy
mState.startDelegating();
@@ -896,6 +955,15 @@
if (mDraggingPointerId == INVALID_POINTER_ID) {
break;
}
+ if (mState.isServiceDetectingGestures()) {
+ // Allow the service to judge whether this is dragging or delegation
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ computeDraggingPointerIdIfNeeded(event);
+ mDispatcher.sendMotionEvent(
+ event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags);
+ return;
+
+ }
switch (event.getPointerCount()) {
case 1:
// do nothing
@@ -921,6 +989,10 @@
}
break;
default:
+ if (mState.isServiceDetectingGestures()) {
+ mAms.sendMotionEventToListeningServices(rawEvent);
+ return;
+ }
mState.startDelegating();
mDraggingPointerId = INVALID_POINTER_ID;
event = MotionEvent.obtainNoHistory(event);
@@ -1210,9 +1282,7 @@
mTouchExplorationPassthroughRegion = region;
}
- /**
- * Whether to send the motion events that make up each gesture to the accessibility service.
- */
+ /** Whether to send the motion events that make up each gesture to the accessibility service. */
public void setSendMotionEventsEnabled(boolean mode) {
mGestureDetector.setSendMotionEventsEnabled(mode);
}
@@ -1221,7 +1291,15 @@
return mGestureDetector.isSendMotionEventsEnabled();
}
+ /** Sets whether or not motion events should be passed to the service to detect gestures. */
+ public void setServiceDetectsGestures(boolean mode) {
+ mState.setServiceDetectsGestures(mode);
+ }
+
private boolean shouldPerformGestureDetection(MotionEvent event) {
+ if (mState.isServiceDetectingGestures()) {
+ return false;
+ }
if (mState.isDelegating() || mState.isDragging()) {
return false;
}
@@ -1237,8 +1315,105 @@
}
/**
- * Class for delayed exiting from gesture detecting mode.
+ * This method allows the service to request that TouchExplorer enter the touch exploration
+ * state.
*/
+ public void requestTouchExploration() {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Starting touch explorer from service.");
+ }
+ if (mState.isServiceDetectingGestures() && mState.isTouchInteracting()) {
+ // Cancel without deleting events.
+ mHandler.removeCallbacks(mSendHoverEnterAndMoveDelayed);
+ mSendHoverEnterAndMoveDelayed.run();
+ mSendHoverEnterAndMoveDelayed.clear();
+ final MotionEvent prototype = mState.getLastReceivedEvent();
+ final MotionEvent rawEvent = mState.getLastReceivedRawEvent();
+ final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+ final int pointerIdBits = (1 << pointerId);
+ final int policyFlags = mState.getLastReceivedPolicyFlags();
+ mSendHoverExitDelayed.post(prototype, rawEvent, pointerIdBits, policyFlags);
+ }
+ }
+
+ /** This method allows the service to request that TouchExplorer enter the dragging state. */
+ public void requestDragging(int pointerId) {
+ if (mState.isServiceDetectingGestures()) {
+ if (pointerId < 0 || pointerId > TouchState.MAX_POINTER_COUNT
+ || !mReceivedPointerTracker.isReceivedPointerDown(pointerId)) {
+ Slog.e(LOG_TAG, "Trying to drag with invalid pointer: " + pointerId);
+ return;
+ }
+ if (mState.isTouchExploring()) {
+ if (mSendHoverExitDelayed.isPending()) {
+ mSendHoverExitDelayed.forceSendAndRemove();
+ }
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+ }
+ if (!mState.isTouchInteracting()) {
+ // It makes no sense to drag.
+ Slog.e(LOG_TAG, "Error: Trying to drag from "
+ + mState.getStateSymbolicName(mState.getState()));
+ return;
+ }
+ mDraggingPointerId = pointerId;
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Drag requested on pointer " + mDraggingPointerId);
+ }
+ MotionEvent event = mState.getLastReceivedEvent();
+ MotionEvent rawEvent = mState.getLastReceivedRawEvent();
+ if (event == null || rawEvent == null) {
+ Slog.e(LOG_TAG, "Unable to start dragging: unable to get last event.");
+ return;
+ }
+ int policyFlags = mState.getLastReceivedPolicyFlags();
+ int pointerIdBits = 1 << mDraggingPointerId;
+ event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
+ MotionEvent downEvent = computeDownEventForDrag(event);
+ mState.startDragging();
+ if (downEvent != null) {
+ mDispatcher.sendMotionEvent(
+ downEvent, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ mDispatcher.sendMotionEvent(event, ACTION_MOVE, rawEvent, pointerIdBits,
+ policyFlags);
+ } else {
+ mDispatcher.sendMotionEvent(event, ACTION_DOWN, rawEvent, pointerIdBits,
+ policyFlags);
+ }
+ }
+ }
+
+ /** This method allows the service to request that TouchExplorer enter the delegating state. */
+ public void requestDelegating() {
+ if (mState.isServiceDetectingGestures()) {
+ if (mState.isTouchExploring()) {
+ if (mSendHoverExitDelayed.isPending()) {
+ mSendHoverExitDelayed.forceSendAndRemove();
+ }
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+ }
+ if (!mState.isTouchInteracting()) {
+ // It makes no sense to delegate.
+ Slog.e(LOG_TAG, "Error: Trying to delegate from "
+ + mState.getStateSymbolicName(mState.getState()));
+ return;
+ }
+ mState.startDelegating();
+ MotionEvent prototype = mState.getLastReceivedEvent();
+ if (prototype == null) {
+ Slog.d(LOG_TAG, "Unable to start delegating: unable to get last received event.");
+ return;
+ }
+ int policyFlags = mState.getLastReceivedPolicyFlags();
+ mDispatcher.sendDownForAllNotInjectedPointers(prototype, policyFlags);
+ }
+ }
+
+ /** Class for delayed exiting from gesture detecting mode. */
private final class ExitGestureDetectionModeDelayed implements Runnable {
public void post() {
@@ -1283,9 +1458,7 @@
}
}
- /**
- * Class for delayed sending of hover enter and move events.
- */
+ /** Class for delayed sending of hover enter and move events. */
class SendHoverEnterAndMoveDelayed implements Runnable {
private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed";
@@ -1362,31 +1535,46 @@
}
if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) {
// Deliver a down event.
- mDispatcher.sendMotionEvent(mEvents.get(0), ACTION_HOVER_ENTER,
- mRawEvents.get(0), mPointerIdBits, mPolicyFlags);
+ mDispatcher.sendMotionEvent(
+ mEvents.get(0),
+ ACTION_HOVER_ENTER,
+ mRawEvents.get(0),
+ mPointerIdBits,
+ mPolicyFlags);
if (DEBUG) {
- Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+ Slog.d(
+ LOG_TAG_SEND_HOVER_DELAYED,
"Injecting motion event: ACTION_HOVER_ENTER");
}
// Deliver move events.
final int eventCount = mEvents.size();
for (int i = 1; i < eventCount; i++) {
- mDispatcher.sendMotionEvent(mEvents.get(i), ACTION_HOVER_MOVE,
- mRawEvents.get(i), mPointerIdBits, mPolicyFlags);
+ mDispatcher.sendMotionEvent(
+ mEvents.get(i),
+ ACTION_HOVER_MOVE,
+ mRawEvents.get(i),
+ mPointerIdBits,
+ mPolicyFlags);
if (DEBUG) {
- Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+ Slog.d(
+ LOG_TAG_SEND_HOVER_DELAYED,
"Injecting motion event: ACTION_HOVER_MOVE");
}
}
}
clear();
}
- }
- /**
- * Class for delayed sending of hover exit events.
- */
+ public void setPointerIdBits(int pointerIdBits) {
+ mPointerIdBits = pointerIdBits;
+ }
+
+ public void setPolicyFlags(int policyFlags) {
+ mPolicyFlags = policyFlags;
+ }
+ }
+ /** Class for delayed sending of hover exit events. */
class SendHoverExitDelayed implements Runnable {
private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed";
@@ -1438,21 +1626,18 @@
public void run() {
if (DEBUG) {
- Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:"
- + " ACTION_HOVER_EXIT");
+ Slog.d(
+ LOG_TAG_SEND_HOVER_DELAYED,
+ "Injecting motion event:" + " ACTION_HOVER_EXIT");
}
mDispatcher.sendMotionEvent(
- mPrototype,
- ACTION_HOVER_EXIT,
- mRawEvent,
- mPointerIdBits,
- mPolicyFlags);
+ mPrototype, ACTION_HOVER_EXIT, mRawEvent, mPointerIdBits, mPolicyFlags);
if (!mSendTouchExplorationEndDelayed.isPending()) {
mSendTouchExplorationEndDelayed.cancel();
mSendTouchExplorationEndDelayed.post();
}
if (mSendTouchInteractionEndDelayed.isPending()) {
- mSendTouchInteractionEndDelayed.cancel();
+ mSendTouchInteractionEndDelayed.cancel();
mSendTouchInteractionEndDelayed.post();
}
clear();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 6ff0826..eb71885 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -22,9 +22,12 @@
import android.annotation.IntDef;
import android.util.Slog;
+import android.view.Display;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityEvent;
+import com.android.server.accessibility.AccessibilityManagerService;
+
/**
* This class describes the state of the touch explorer as well as the state of received and
* injected pointers. This data is accessed both for purposes of touch exploration and gesture
@@ -36,7 +39,7 @@
// This constant captures the current implementation detail that
// pointer IDs are between 0 and 31 inclusive (subject to change).
// (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
- static final int MAX_POINTER_COUNT = 32;
+ public static final int MAX_POINTER_COUNT = 32;
// Constant referring to the ids bits of all pointers.
public static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF;
@@ -50,8 +53,8 @@
public static final int STATE_TOUCH_EXPLORING = 2;
// the user is dragging with two fingers.
public static final int STATE_DRAGGING = 3;
- // The user is performing some other two finger gesture which we pass through to the view
- // hierarchy as a one-finger gesture e.g. two-finger scrolling.
+ // The user is performing some other two finger gesture which we pass through to the
+ // input pipeline as a one-finger gesture e.g. two-finger pinch.
public static final int STATE_DELEGATING = 4;
// The user is performing something that might be a gesture.
public static final int STATE_GESTURE_DETECTING = 5;
@@ -75,6 +78,8 @@
private MotionEvent mLastReceivedEvent;
// The accompanying raw event without any transformations.
private MotionEvent mLastReceivedRawEvent;
+ // The policy flags of the last received event.
+ int mLastReceivedPolicyFlags;
// The id of the last touch explored window.
private int mLastTouchedWindowId;
// The last injected hover event.
@@ -85,14 +90,23 @@
private long mLastInjectedDownEventTime;
// Keep track of which pointers sent to the system are down.
private int mInjectedPointersDown;
+ private boolean mServiceDetectsGestures = false;
+ // The requested mode for mServiceDetectsGestures. This will take effect on the next touch
+ // interaction.
+ private boolean mServiceDetectsGesturesRequested = false;
+ private AccessibilityManagerService mAms;
+ private int mDisplayId = Display.INVALID_DISPLAY;
- public TouchState() {
+ public TouchState(int displayId, AccessibilityManagerService ams) {
+ mDisplayId = displayId;
+ mAms = ams;
mReceivedPointerTracker = new ReceivedPointerTracker();
}
/** Clears the internal shared state. */
public void clear() {
setState(STATE_CLEAR);
+ mServiceDetectsGestures = mServiceDetectsGesturesRequested;
// Reset the pointer trackers.
if (mLastReceivedEvent != null) {
mLastReceivedEvent.recycle();
@@ -107,14 +121,19 @@
*
* @param rawEvent The raw touch event.
*/
- public void onReceivedMotionEvent(MotionEvent rawEvent) {
+ public void onReceivedMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (isClear() && event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ clear();
+ }
if (mLastReceivedEvent != null) {
mLastReceivedEvent.recycle();
}
if (mLastReceivedRawEvent != null) {
mLastReceivedRawEvent.recycle();
}
- mLastReceivedEvent = MotionEvent.obtain(rawEvent);
+ mLastReceivedEvent = MotionEvent.obtain(event);
+ mLastReceivedRawEvent = MotionEvent.obtain(rawEvent);
+ mLastReceivedPolicyFlags = policyFlags;
mReceivedPointerTracker.onMotionEvent(rawEvent);
}
@@ -123,7 +142,7 @@
*
* @param event The event to process.
*/
- void onInjectedMotionEvent(MotionEvent event) {
+ public void onInjectedMotionEvent(MotionEvent event) {
final int action = event.getActionMasked();
final int pointerId = event.getPointerId(event.getActionIndex());
final int pointerFlag = (1 << pointerId);
@@ -183,6 +202,7 @@
}
}
+ /** Updates the state in response to an injected accessibility event. */
public void onInjectedAccessibilityEvent(int type) {
// The below state transitions go here because the related events are often sent on a
// delay.
@@ -195,7 +215,8 @@
startTouchInteracting();
break;
case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
- clear();
+ setState(STATE_CLEAR);
+ // We will clear when we actually handle the next ACTION_DOWN.
break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
startTouchExploring();
@@ -228,6 +249,9 @@
Slog.i(LOG_TAG, getStateSymbolicName(mState) + "->" + getStateSymbolicName(state));
}
mState = state;
+ if (mServiceDetectsGestures) {
+ mAms.onTouchStateChanged(mDisplayId, state);
+ }
}
public boolean isTouchExploring() {
@@ -314,6 +338,16 @@
return mLastReceivedEvent;
}
+ /** Gets the most recently received policy flags. */
+ public int getLastReceivedPolicyFlags() {
+ return mLastReceivedPolicyFlags;
+ }
+
+ /** Gets the most recently received raw event. */
+ public MotionEvent getLastReceivedRawEvent() {
+ return mLastReceivedRawEvent;
+ }
+
/** @return The the last injected hover event. */
public MotionEvent getLastInjectedHoverEvent() {
return mLastInjectedHoverEvent;
@@ -354,6 +388,18 @@
return mLastInjectedHoverEventForClick;
}
+ public boolean isServiceDetectingGestures() {
+ return mServiceDetectsGestures;
+ }
+
+ /** Whether the service is handling gesture detection. */
+ public void setServiceDetectsGestures(boolean mode) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "serviceDetectsGestures: " + mode);
+ }
+ mServiceDetectsGesturesRequested = mode;
+ }
+
/** This class tracks where and when a pointer went down. It does not track its movement. */
class ReceivedPointerTracker {
private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fab58e8..b72b095 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1164,17 +1164,6 @@
remove(r.binder);
}
}
- if (events.contains(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- updateReportSignalStrengthDecision(r.subId);
- try {
- if (mSignalStrength[r.phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
- }
- }
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) {
try {
@@ -1353,27 +1342,6 @@
}
}
- private void updateReportSignalStrengthDecision(int subscriptionId) {
- synchronized (mRecords) {
- TelephonyManager telephonyManager = (TelephonyManager) mContext
- .getSystemService(Context.TELEPHONY_SERVICE);
- for (Record r : mRecords) {
- // If any of the system clients wants to always listen to signal strength,
- // we need to set it on.
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- telephonyManager.createForSubscriptionId(subscriptionId)
- .setAlwaysReportSignalStrength(true);
- return;
- }
- }
- // If none of the system clients wants to always listen to signal strength,
- // we need to set it off.
- telephonyManager.createForSubscriptionId(subscriptionId)
- .setAlwaysReportSignalStrength(false);
- }
- }
-
private String getCallIncomingNumber(Record record, int phoneId) {
// Only reveal the incoming number if the record has read call log permission.
return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
@@ -1457,14 +1425,6 @@
}
mRecords.remove(i);
-
- // Every time a client that is registrating to always receive the signal
- // strength is removed from registry records, we need to check if
- // the signal strength decision needs to update on its slot.
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- updateReportSignalStrengthDecision(r.subId);
- }
return;
}
}
@@ -1696,10 +1656,8 @@
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if ((r.matchTelephonyCallbackEvent(
+ if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
- || r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
&& idMatch(r, subId, phoneId)) {
try {
if (DBG) {
@@ -3120,11 +3078,6 @@
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
- if ((events.contains(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
- }
-
if (isPrivilegedPhoneStatePermissionRequired(events)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
@@ -3285,9 +3238,7 @@
}
}
- if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
- || events.contains(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cf4d048..c22c90e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,6 +31,7 @@
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
@@ -15330,6 +15331,11 @@
}
@Override
+ public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ mUserController.setStopBackgroundUsersOnSwitch(value);
+ }
+
+ @Override
public int stopUser(final int userId, boolean force, final IStopUserCallback callback) {
return mUserController.stopUser(userId, force, /* allowDelayedLocking= */ false,
/* callback= */ callback, /* keyEvictedCallback= */ null);
@@ -16652,6 +16658,11 @@
@Nullable ActivityManagerInternal.VoiceInteractionManagerProvider provider) {
ActivityManagerService.this.setVoiceInteractionManagerProvider(provider);
}
+
+ @Override
+ public void setStopBackgroundUsersOnSwitch(int value) {
+ ActivityManagerService.this.setStopBackgroundUsersOnSwitch(value);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 0f71639..25adddd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -29,6 +29,8 @@
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import android.app.ActivityManager;
@@ -100,6 +102,7 @@
import com.android.internal.util.MemInfoReader;
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.compat.PlatformCompat;
+import com.android.server.utils.Slogf;
import java.io.BufferedReader;
import java.io.IOException;
@@ -128,6 +131,10 @@
import javax.microedition.khronos.egl.EGLSurface;
final class ActivityManagerShellCommand extends ShellCommand {
+
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerShellCommand" : TAG_AM;
+
+
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
@@ -325,6 +332,8 @@
return runServiceRestartBackoff(pw);
case "get-isolated-pids":
return runGetIsolatedProcesses(pw);
+ case "set-stop-user-on-switch":
+ return runSetStopBackgroundUsersOnSwitch(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3175,6 +3184,30 @@
return 0;
}
+ private int runSetStopBackgroundUsersOnSwitch(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "setStopBackgroundUsersOnSwitch()");
+ String arg = getNextArg();
+ if (arg == null) {
+ Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): resetting to default value");
+ mInternal.setStopBackgroundUsersOnSwitch(
+ ActivityManager.STOP_BG_USERS_ON_SWITCH_DEFAULT);
+ pw.println("Reset to default value");
+ return 0;
+ }
+
+ boolean stop = Boolean.parseBoolean(arg);
+ int value = stop
+ ? ActivityManager.STOP_BG_USERS_ON_SWITCH_TRUE
+ : ActivityManager.STOP_BG_USERS_ON_SWITCH_FALSE;
+
+ Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): setting to %d (%b)", value, stop);
+ mInternal.setStopBackgroundUsersOnSwitch(value);
+ pw.println("Set to " + stop);
+
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
@@ -3507,6 +3540,10 @@
pw.println(" Shows the restart backoff policy state for <PACKAGE_NAME>.");
pw.println(" get-isolated-pids <UID>");
pw.println(" Get the PIDs of isolated processes with packages in this <UID>");
+ pw.println(" set-stop-user-on-switch [true|false]");
+ pw.println(" Sets whether the current user (and its profiles) should be stopped"
+ + " when switching to a different user.");
+ pw.println(" Without arguments, it resets to the value defined by platform.");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index fa7eae3..0c518a0 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -19,6 +19,9 @@
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.STOP_BG_USERS_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_BG_USERS_ON_SWITCH_TRUE;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
@@ -368,6 +371,13 @@
@GuardedBy("mLock")
private boolean mInitialized;
+ /**
+ * Defines the behavior of whether the background users should be stopped when the foreground
+ * user is switched.
+ */
+ @GuardedBy("mLock")
+ private @StopBgUsersOnSwitch int mStopBgUsersOnSwitch = STOP_BG_USERS_ON_SWITCH_DEFAULT;
+
UserController(ActivityManagerService service) {
this(new Injector(service));
}
@@ -408,8 +418,33 @@
}
}
+ void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
+ == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException(
+ "You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
+ + "call setStopBackgroundUsersOnSwitch()");
+ }
+
+ synchronized (mLock) {
+ Slogf.i(TAG, "setStopBackgroundUsersOnSwitch(): %d -> %d",
+ mStopBgUsersOnSwitch, value);
+ mStopBgUsersOnSwitch = value;
+ }
+ }
+
private boolean shouldStopBackgroundUsersOnSwitch() {
- int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
+ synchronized (mLock) {
+ if (mStopBgUsersOnSwitch != STOP_BG_USERS_ON_SWITCH_DEFAULT) {
+ final boolean value = mStopBgUsersOnSwitch == STOP_BG_USERS_ON_SWITCH_TRUE;
+ Slogf.i(TAG, "isStopBackgroundUsersOnSwitch(): returning overridden value (%b)",
+ value);
+ return value;
+ }
+ }
+ final int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
return property == -1 ? mDelayUserDataLocking : property == 1;
}
@@ -2636,8 +2671,9 @@
pw.println(" mTargetUserId:" + mTargetUserId);
pw.println(" mLastActiveUsers:" + mLastActiveUsers);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
- pw.println(" shouldStopBackgroundUsersOnSwitch:"
+ pw.println(" shouldStopBackgroundUsersOnSwitch():"
+ shouldStopBackgroundUsersOnSwitch());
+ pw.println(" mStopBgUsersOnSwitch:" + mStopBgUsersOnSwitch);
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
pw.println(" mInitialized:" + mInitialized);
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 8c1a90c..fc0ee23 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,7 +1,3 @@
include platform/frameworks/base:/core/java/android/permission/OWNERS
-per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
-per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
-per-file DefaultPermissionGrantPolicy.java = toddke@google.com
-per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
-per-file DefaultPermissionGrantPolicy.java = patb@google.com
+per-file DefaultPermissionGrantPolicy.java = file:platform/frameworks/base:/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index 3a9b2dc..cb52e5f 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -19,6 +19,7 @@
import static java.util.stream.Collectors.toMap;
import android.Manifest;
+import android.content.ComponentName;
import android.content.Context;
import android.os.ISystemConfig;
import android.util.ArrayMap;
@@ -87,14 +88,14 @@
}
@Override
- public List<String> getEnabledComponentOverrides(String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(String packageName) {
ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance()
.getComponentsEnabledStates(packageName);
- List<String> enabledComponent = new ArrayList<>();
+ List<ComponentName> enabledComponent = new ArrayList<>();
if (systemComponents != null) {
for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) {
if (Boolean.TRUE.equals(entry.getValue())) {
- enabledComponent.add(entry.getKey());
+ enabledComponent.add(new ComponentName(packageName, entry.getKey()));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
index 0e78785..45f0e67 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
@@ -27,18 +27,20 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Handler;
+import android.view.Display;
import android.view.MotionEvent;
import androidx.test.InstrumentationRegistry;
+import com.android.server.accessibility.AccessibilityManagerService;
+
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
import java.util.ArrayList;
-/**
- * Tests for GestureManifold
- */
+/** Tests for GestureManifold */
public class GestureManifoldTest {
// Constants for testRecognizeGesturePath()
@@ -50,25 +52,23 @@
private GestureManifold mManifold;
private TouchState mState;
private GestureManifold.Listener mResultListener;
+ @Mock private AccessibilityManagerService mMockAms;
@Before
public void setUp() {
Context context = InstrumentationRegistry.getContext();
// Construct a testable GestureManifold.
mResultListener = mock(GestureManifold.Listener.class);
- mState = new TouchState();
+ mState = new TouchState(Display.DEFAULT_DISPLAY, mMockAms);
Handler handler = new Handler(context.getMainLooper());
mManifold = new GestureManifold(context, mResultListener, mState, handler);
// Play the role of touch explorer in updating the shared state.
when(mResultListener.onGestureStarted()).thenReturn(onGestureStarted());
-
-
}
-
@Test
public void testRecognizeGesturePath() {
- final int d = 1000; // Length of each segment in the test gesture, in pixels.
+ final int d = 1000; // Length of each segment in the test gesture, in pixels.
testPath(p(-d, +0), AccessibilityService.GESTURE_SWIPE_LEFT);
testPath(p(+d, +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
@@ -138,9 +138,10 @@
// For each path step from start (non-inclusive) to end ... add a motion point.
for (int step = 1; step < numSteps; ++step) {
- path.add(new PointF(
- (start.x + (stepX * (float) step)),
- (start.y + (stepY * (float) step))));
+ path.add(
+ new PointF(
+ (start.x + (stepX * (float) step)),
+ (start.y + (stepY * (float) step))));
}
}
@@ -164,11 +165,12 @@
} else if (pointIndex == path.size() - 1) {
action = MotionEvent.ACTION_UP;
}
- MotionEvent event = MotionEvent.obtain(eventDownTimeMs, eventTimeMs, action,
- point.x, point.y, 0);
+ MotionEvent event =
+ MotionEvent.obtain(eventDownTimeMs, eventTimeMs, action, point.x, point.y, 0);
// Send event.
- mState.onReceivedMotionEvent(event);
+ // In this case the event and raw event values are the same.
+ mState.onReceivedMotionEvent(event, event, policyFlags);
mManifold.onMotionEvent(event, event, policyFlags);
eventTimeMs += PATH_STEP_MILLISEC;
if (mState.isClear()) {
@@ -178,8 +180,9 @@
mState.clear();
// Check that correct gesture was recognized.
- verify(mResultListener).onGestureCompleted(
- argThat(gestureEvent -> gestureEvent.getGestureId() == gestureId));
+ verify(mResultListener)
+ .onGestureCompleted(
+ argThat(gestureEvent -> gestureEvent.getGestureId() == gestureId));
}
private boolean onGestureStarted() {
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index 41e24dd..2ff4ac5 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -66,10 +68,15 @@
private final IBinder mLiveToken;
private SignalStrengthUpdateRequest(
- @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+ @Nullable List<SignalThresholdInfo> signalThresholdInfos,
boolean isReportingRequestedWhileIdle,
boolean isSystemThresholdReportingRequestedWhileIdle) {
- validate(signalThresholdInfos);
+ // System app (like Bluetooth) can specify the request to report system thresholds while
+ // device is idle (with permission protection). In this case, the request doesn't need to
+ // provide a non-empty list of SignalThresholdInfo which is only asked for public apps.
+ if (!isSystemThresholdReportingRequestedWhileIdle) {
+ validate(signalThresholdInfos);
+ }
mSignalThresholdInfos = signalThresholdInfos;
mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
@@ -128,13 +135,15 @@
/**
* Set the builder object if require reporting on the system thresholds when device is idle.
*
- * This can only used by the system caller.
+ * <p>This can only used by the system caller. Requires permission
+ * {@link android.Manifest.permission#LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH}.
*
* @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
* system thresholds when device is idle
* @return the builder to facilitate the chaining
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
boolean isSystemThresholdReportingRequestedWhileIdle) {
mIsSystemThresholdReportingRequestedWhileIdle =
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9c52220..0236306 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -12524,26 +12524,6 @@
}
/**
- * Enable or disable signal strength changes from radio will always be reported in any
- * condition (e.g. screen is off). This is only allowed for System caller.
- *
- * @param isEnabled {@code true} for enabling; {@code false} for disabling.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setAlwaysReportSignalStrength(boolean isEnabled) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex);
- ex.rethrowAsRuntimeException();
- }
- }
-
- /**
* Get the most recently available signal strength information.
*
* Get the most recent SignalStrength information reported by the modem. Due
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 6765576..b3c5d042 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1003,11 +1003,6 @@
boolean isManualNetworkSelectionAllowed(int subId);
/**
- * Enable or disable always reporting signal strength changes from radio.
- */
- void setAlwaysReportSignalStrength(int subId, boolean isEnable);
-
- /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @param callingPackage The package making the call.