Merge "Replace syncInputWindows with addWindowInfosReportedListener"
This commit is contained in:
committed by
Android (Google) Code Review
commit
c42a3c75f7
@@ -233,7 +233,8 @@ public final class SurfaceControl implements Parcelable {
|
||||
private static native boolean nativeGetProtectedContentSupport();
|
||||
private static native void nativeSetMetadata(long transactionObj, long nativeObject, int key,
|
||||
Parcel data);
|
||||
private static native void nativeSyncInputWindows(long transactionObj);
|
||||
private static native void nativeAddWindowInfosReportedListener(long transactionObj,
|
||||
Runnable listener);
|
||||
private static native boolean nativeGetDisplayBrightnessSupport(IBinder displayToken);
|
||||
private static native boolean nativeSetDisplayBrightness(IBinder displayToken,
|
||||
float sdrBrightness, float sdrBrightnessNits, float displayBrightness,
|
||||
@@ -3061,13 +3062,14 @@ public final class SurfaceControl implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until any changes to input windows have been sent from SurfaceFlinger to
|
||||
* InputFlinger before returning.
|
||||
* Adds a callback that is called after WindowInfosListeners from the systems server are
|
||||
* complete. This is primarily used to ensure that InputDispatcher::setInputWindowsLocked
|
||||
* has been called before running the added callback.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Transaction syncInputWindows() {
|
||||
nativeSyncInputWindows(mNativeObject);
|
||||
public Transaction addWindowInfosReportedListener(@NonNull Runnable listener) {
|
||||
nativeAddWindowInfosReportedListener(mNativeObject, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,12 @@
|
||||
#define LOG_TAG "SurfaceControl"
|
||||
#define LOG_NDEBUG 0
|
||||
|
||||
#include "android_os_Parcel.h"
|
||||
#include "android_util_Binder.h"
|
||||
#include "android_hardware_input_InputWindowHandle.h"
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android/graphics/properties.h>
|
||||
#include <android/graphics/region.h>
|
||||
#include <android/gui/BnScreenCaptureListener.h>
|
||||
#include <android/gui/BnWindowInfosReportedListener.h>
|
||||
#include <android/hardware/display/IDeviceProductInfoConstants.h>
|
||||
#include <android/os/IInputConstants.h>
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
@@ -60,6 +54,13 @@
|
||||
#include <utils/LightRefBase.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "android_hardware_input_InputWindowHandle.h"
|
||||
#include "android_os_Parcel.h"
|
||||
#include "android_util_Binder.h"
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
@@ -87,6 +88,11 @@ static jobject toInteger(JNIEnv* env, int32_t i) {
|
||||
return env->NewObject(gIntegerClassInfo.clazz, gIntegerClassInfo.ctor, i);
|
||||
}
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
jmethodID run;
|
||||
} gRunnableClassInfo;
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
jmethodID ctor;
|
||||
@@ -381,6 +387,38 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class WindowInfosReportedListenerWrapper : public gui::BnWindowInfosReportedListener {
|
||||
public:
|
||||
explicit WindowInfosReportedListenerWrapper(JNIEnv* env, jobject listener) {
|
||||
env->GetJavaVM(&mVm);
|
||||
mListener = env->NewGlobalRef(listener);
|
||||
LOG_ALWAYS_FATAL_IF(!mListener, "Failed to make global ref");
|
||||
}
|
||||
|
||||
~WindowInfosReportedListenerWrapper() {
|
||||
if (mListener) {
|
||||
getenv()->DeleteGlobalRef(mListener);
|
||||
mListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
binder::Status onWindowInfosReported() override {
|
||||
JNIEnv* env = getenv();
|
||||
env->CallVoidMethod(mListener, gRunnableClassInfo.run);
|
||||
return binder::Status::ok();
|
||||
}
|
||||
|
||||
private:
|
||||
jobject mListener;
|
||||
JavaVM* mVm;
|
||||
|
||||
JNIEnv* getenv() {
|
||||
JNIEnv* env;
|
||||
mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
|
||||
return env;
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
|
||||
@@ -890,9 +928,11 @@ static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactio
|
||||
transaction->setInputWindowInfo(ctrl, *handle->getInfo());
|
||||
}
|
||||
|
||||
static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) {
|
||||
static void nativeAddWindowInfosReportedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
|
||||
jobject runnable) {
|
||||
auto listener = sp<WindowInfosReportedListenerWrapper>::make(env, runnable);
|
||||
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
|
||||
transaction->syncInputWindows();
|
||||
transaction->addWindowInfosReportedListener(listener);
|
||||
}
|
||||
|
||||
static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj,
|
||||
@@ -2258,8 +2298,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
|
||||
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
|
||||
{"nativeSetDataSpace", "(JJI)V",
|
||||
(void*)nativeSetDataSpace },
|
||||
{"nativeSyncInputWindows", "(J)V",
|
||||
(void*)nativeSyncInputWindows },
|
||||
{"nativeAddWindowInfosReportedListener", "(JLjava/lang/Runnable;)V",
|
||||
(void*)nativeAddWindowInfosReportedListener },
|
||||
{"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
|
||||
(void*)nativeGetDisplayBrightnessSupport },
|
||||
{"nativeSetDisplayBrightness", "(Landroid/os/IBinder;FFFF)Z",
|
||||
@@ -2323,6 +2363,10 @@ int register_android_view_SurfaceControl(JNIEnv* env)
|
||||
gIntegerClassInfo.clazz = MakeGlobalRefOrDie(env, integerClass);
|
||||
gIntegerClassInfo.ctor = GetMethodIDOrDie(env, gIntegerClassInfo.clazz, "<init>", "(I)V");
|
||||
|
||||
jclass runnableClazz = FindClassOrDie(env, "java/lang/Runnable");
|
||||
gRunnableClassInfo.clazz = MakeGlobalRefOrDie(env, runnableClazz);
|
||||
gRunnableClassInfo.run = GetMethodIDOrDie(env, runnableClazz, "run", "()V");
|
||||
|
||||
jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$StaticDisplayInfo");
|
||||
gStaticDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz);
|
||||
gStaticDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V");
|
||||
|
||||
@@ -38,6 +38,8 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -106,6 +108,8 @@ class DragDropController {
|
||||
final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken,
|
||||
touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
|
||||
try {
|
||||
DisplayContent displayContent = null;
|
||||
CompletableFuture<Boolean> touchFocusTransferredFuture = null;
|
||||
synchronized (mService.mGlobalLock) {
|
||||
try {
|
||||
if (!callbackResult) {
|
||||
@@ -137,7 +141,7 @@ class DragDropController {
|
||||
|
||||
// !!! TODO(multi-display): support other displays
|
||||
|
||||
final DisplayContent displayContent = callingWin.getDisplayContent();
|
||||
displayContent = callingWin.getDisplayContent();
|
||||
if (displayContent == null) {
|
||||
Slog.w(TAG_WM, "display content is null");
|
||||
return null;
|
||||
@@ -158,33 +162,9 @@ class DragDropController {
|
||||
|
||||
if ((flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) == 0) {
|
||||
final Display display = displayContent.getDisplay();
|
||||
if (!mCallback.get().registerInputChannel(
|
||||
touchFocusTransferredFuture = mCallback.get().registerInputChannel(
|
||||
mDragState, display, mService.mInputManager,
|
||||
callingWin.mInputChannel)) {
|
||||
Slog.e(TAG_WM, "Unable to transfer touch focus");
|
||||
return null;
|
||||
}
|
||||
|
||||
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
|
||||
mDragState.broadcastDragStartedLocked(touchX, touchY);
|
||||
mDragState.overridePointerIconLocked(touchSource);
|
||||
// remember the thumb offsets for later
|
||||
mDragState.mThumbOffsetX = thumbCenterX;
|
||||
mDragState.mThumbOffsetY = thumbCenterY;
|
||||
|
||||
// Make the surface visible at the proper location
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
|
||||
}
|
||||
|
||||
final SurfaceControl.Transaction transaction = mDragState.mTransaction;
|
||||
transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
|
||||
transaction.show(surfaceControl);
|
||||
displayContent.reparentToOverlay(transaction, surfaceControl);
|
||||
mDragState.updateDragSurfaceLocked(true, touchX, touchY);
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
|
||||
}
|
||||
callingWin.mInputChannel);
|
||||
} else {
|
||||
// Skip surface logic for a drag triggered by an AccessibilityAction
|
||||
mDragState.broadcastDragStartedLocked(touchX, touchY);
|
||||
@@ -194,14 +174,51 @@ class DragDropController {
|
||||
getAccessibilityManager().getRecommendedTimeoutMillis(
|
||||
A11Y_DRAG_TIMEOUT_DEFAULT_MS,
|
||||
AccessibilityManager.FLAG_CONTENT_CONTROLS));
|
||||
|
||||
return dragToken;
|
||||
}
|
||||
} finally {
|
||||
if (surface != null) {
|
||||
surface.release();
|
||||
}
|
||||
if (mDragState != null && !mDragState.isInProgress()) {
|
||||
mDragState.closeLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean touchFocusTransferred = false;
|
||||
try {
|
||||
touchFocusTransferred = touchFocusTransferredFuture.get(DRAG_TIMEOUT_MS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (Exception exception) {
|
||||
Slog.e(TAG_WM, "Exception thrown while waiting for touch focus transfer",
|
||||
exception);
|
||||
}
|
||||
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (!touchFocusTransferred) {
|
||||
Slog.e(TAG_WM, "Unable to transfer touch focus");
|
||||
mDragState.closeLocked();
|
||||
return null;
|
||||
}
|
||||
|
||||
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
|
||||
mDragState.broadcastDragStartedLocked(touchX, touchY);
|
||||
mDragState.overridePointerIconLocked(touchSource);
|
||||
// remember the thumb offsets for later
|
||||
mDragState.mThumbOffsetX = thumbCenterX;
|
||||
mDragState.mThumbOffsetY = thumbCenterY;
|
||||
|
||||
// Make the surface visible at the proper location
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
|
||||
}
|
||||
|
||||
final SurfaceControl.Transaction transaction = mDragState.mTransaction;
|
||||
transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
|
||||
transaction.show(surfaceControl);
|
||||
displayContent.reparentToOverlay(transaction, surfaceControl);
|
||||
mDragState.updateDragSurfaceLocked(true, touchX, touchY);
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
|
||||
}
|
||||
}
|
||||
return dragToken; // success!
|
||||
|
||||
@@ -34,6 +34,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
import static com.android.server.wm.WindowManagerService.MY_PID;
|
||||
import static com.android.server.wm.WindowManagerService.MY_UID;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
@@ -70,6 +72,7 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Drag/drop state
|
||||
@@ -160,7 +163,10 @@ class DragState {
|
||||
return mIsClosing;
|
||||
}
|
||||
|
||||
private void showInputSurface() {
|
||||
/**
|
||||
* @return a future that completes after window info is sent.
|
||||
*/
|
||||
private CompletableFuture<Void> showInputSurface() {
|
||||
if (mInputSurface == null) {
|
||||
mInputSurface = mService.makeSurfaceBuilder(mDisplayContent.getSession())
|
||||
.setContainerLayer()
|
||||
@@ -173,7 +179,7 @@ class DragState {
|
||||
if (h == null) {
|
||||
Slog.w(TAG_WM, "Drag is in progress but there is no "
|
||||
+ "drag window handle.");
|
||||
return;
|
||||
return completedFuture(null);
|
||||
}
|
||||
|
||||
// Crop the input surface to the display size.
|
||||
@@ -184,10 +190,13 @@ class DragState {
|
||||
.setLayer(mInputSurface, Integer.MAX_VALUE)
|
||||
.setCrop(mInputSurface, mTmpClipRect);
|
||||
|
||||
// syncInputWindows here to ensure the input window info is sent before the
|
||||
// A completableFuture is returned to ensure that input window info is sent before the
|
||||
// transferTouchFocus is called.
|
||||
mTransaction.syncInputWindows()
|
||||
.apply(true /*sync*/);
|
||||
CompletableFuture<Void> result = new CompletableFuture<>();
|
||||
mTransaction
|
||||
.addWindowInfosReportedListener(() -> result.complete(null))
|
||||
.apply();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -416,14 +425,15 @@ class DragState {
|
||||
/**
|
||||
* @param display The Display that the window being dragged is on.
|
||||
*/
|
||||
void register(Display display) {
|
||||
CompletableFuture<Void> register(Display display) {
|
||||
display.getRealSize(mDisplaySize);
|
||||
if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
|
||||
if (mInputInterceptor != null) {
|
||||
Slog.e(TAG_WM, "Duplicate register of drag input channel");
|
||||
return completedFuture(null);
|
||||
} else {
|
||||
mInputInterceptor = new InputInterceptor(display);
|
||||
showInputSurface();
|
||||
return showInputSurface();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,13 +150,13 @@ final class InputMonitor {
|
||||
|
||||
void onDisplayRemoved() {
|
||||
mHandler.removeCallbacks(mUpdateInputWindows);
|
||||
mHandler.post(() -> {
|
||||
// Make sure any pending setInputWindowInfo transactions are completed. That prevents
|
||||
// the timing of updating input info of removed display after cleanup.
|
||||
mService.mTransactionFactory.get().syncInputWindows().apply();
|
||||
// It calls InputDispatcher::setInputWindows directly.
|
||||
mService.mInputManager.onDisplayRemoved(mDisplayId);
|
||||
});
|
||||
mService.mTransactionFactory.get()
|
||||
// Make sure any pending setInputWindowInfo transactions are completed. That
|
||||
// prevents the timing of updating input info of removed display after cleanup.
|
||||
.addWindowInfosReportedListener(() ->
|
||||
// It calls InputDispatcher::setInputWindows directly.
|
||||
mService.mInputManager.onDisplayRemoved(mDisplayId))
|
||||
.apply();
|
||||
mDisplayRemoved = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ import static com.android.server.wm.WindowManagerService.dipToPixel;
|
||||
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
|
||||
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -60,6 +62,8 @@ import com.android.internal.policy.TaskResizingAlgorithm;
|
||||
import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
class TaskPositioner implements IBinder.DeathRecipient {
|
||||
private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false;
|
||||
private static final String TAG_LOCAL = "TaskPositioner";
|
||||
@@ -195,14 +199,14 @@ class TaskPositioner implements IBinder.DeathRecipient {
|
||||
* @param displayContent The Display that the window being dragged is on.
|
||||
* @param win The window which will be dragged.
|
||||
*/
|
||||
void register(DisplayContent displayContent, @NonNull WindowState win) {
|
||||
CompletableFuture<Void> register(DisplayContent displayContent, @NonNull WindowState win) {
|
||||
if (DEBUG_TASK_POSITIONING) {
|
||||
Slog.d(TAG, "Registering task positioner");
|
||||
}
|
||||
|
||||
if (mClientChannel != null) {
|
||||
Slog.e(TAG, "Task positioner already registered");
|
||||
return;
|
||||
return completedFuture(null);
|
||||
}
|
||||
|
||||
mDisplayContent = displayContent;
|
||||
@@ -235,27 +239,33 @@ class TaskPositioner implements IBinder.DeathRecipient {
|
||||
mDisplayContent.getDisplayRotation().pause();
|
||||
|
||||
// Notify InputMonitor to take mDragWindowHandle.
|
||||
mService.mTaskPositioningController.showInputSurface(win.getDisplayId());
|
||||
return mService.mTaskPositioningController.showInputSurface(win.getDisplayId())
|
||||
.thenRun(() -> {
|
||||
// The global lock is held by the callers of register but released before the async
|
||||
// results are waited on. We must acquire the lock in this callback to ensure thread
|
||||
// safety.
|
||||
synchronized (mService.mGlobalLock) {
|
||||
final Rect displayBounds = mTmpRect;
|
||||
displayContent.getBounds(displayBounds);
|
||||
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
|
||||
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
|
||||
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
|
||||
mMaxVisibleSize.set(displayBounds.width(), displayBounds.height());
|
||||
|
||||
final Rect displayBounds = mTmpRect;
|
||||
displayContent.getBounds(displayBounds);
|
||||
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
|
||||
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
|
||||
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
|
||||
mMaxVisibleSize.set(displayBounds.width(), displayBounds.height());
|
||||
mDragEnded = false;
|
||||
|
||||
mDragEnded = false;
|
||||
|
||||
try {
|
||||
mClientCallback = win.mClient.asBinder();
|
||||
mClientCallback.linkToDeath(this, 0 /* flags */);
|
||||
} catch (RemoteException e) {
|
||||
// The caller has died, so clean up TaskPositioningController.
|
||||
mService.mTaskPositioningController.finishTaskPositioning();
|
||||
return;
|
||||
}
|
||||
mWindow = win;
|
||||
mTask = win.getTask();
|
||||
try {
|
||||
mClientCallback = win.mClient.asBinder();
|
||||
mClientCallback.linkToDeath(this, 0 /* flags */);
|
||||
} catch (RemoteException e) {
|
||||
// The caller has died, so clean up TaskPositioningController.
|
||||
mService.mTaskPositioningController.finishTaskPositioning();
|
||||
return;
|
||||
}
|
||||
mWindow = win;
|
||||
mTask = win.getTask();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void unregister() {
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.wm;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -28,6 +30,8 @@ import android.view.IWindow;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Controller for task positioning by drag.
|
||||
*/
|
||||
@@ -58,14 +62,16 @@ class TaskPositioningController {
|
||||
void hideInputSurface(int displayId) {
|
||||
if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId
|
||||
&& mInputSurface != null) {
|
||||
mTransaction.hide(mInputSurface);
|
||||
mTransaction.syncInputWindows().apply();
|
||||
mTransaction.hide(mInputSurface).apply();
|
||||
}
|
||||
}
|
||||
|
||||
void showInputSurface(int displayId) {
|
||||
/**
|
||||
* @return a future that completes after window info is sent.
|
||||
*/
|
||||
CompletableFuture<Void> showInputSurface(int displayId) {
|
||||
if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) {
|
||||
return;
|
||||
return completedFuture(null);
|
||||
}
|
||||
final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
|
||||
if (mInputSurface == null) {
|
||||
@@ -81,7 +87,7 @@ class TaskPositioningController {
|
||||
if (h == null) {
|
||||
Slog.w(TAG_WM, "Drag is in progress but there is no "
|
||||
+ "drag window handle.");
|
||||
return;
|
||||
return completedFuture(null);
|
||||
}
|
||||
|
||||
final Display display = dc.getDisplay();
|
||||
@@ -89,25 +95,38 @@ class TaskPositioningController {
|
||||
display.getRealSize(p);
|
||||
mTmpClipRect.set(0, 0, p.x, p.y);
|
||||
|
||||
CompletableFuture<Void> result = new CompletableFuture<>();
|
||||
mTransaction.show(mInputSurface)
|
||||
.setInputWindowInfo(mInputSurface, h)
|
||||
.setLayer(mInputSurface, Integer.MAX_VALUE)
|
||||
.setPosition(mInputSurface, 0, 0)
|
||||
.setCrop(mInputSurface, mTmpClipRect)
|
||||
.syncInputWindows()
|
||||
.addWindowInfosReportedListener(() -> result.complete(null))
|
||||
.apply();
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean startMovingTask(IWindow window, float startX, float startY) {
|
||||
WindowState win = null;
|
||||
CompletableFuture<Boolean> startPositioningLockedFuture;
|
||||
synchronized (mService.mGlobalLock) {
|
||||
win = mService.windowForClientLocked(null, window, false);
|
||||
// win shouldn't be null here, pass it down to startPositioningLocked
|
||||
// to get warning if it's null.
|
||||
if (!startPositioningLocked(
|
||||
win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
|
||||
startPositioningLockedFuture =
|
||||
startPositioningLocked(
|
||||
win, false /*resize*/, false /*preserveOrientation*/, startX, startY);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!startPositioningLockedFuture.get()) {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Slog.e(TAG_WM, "Exception thrown while waiting for startPositionLocked future",
|
||||
exception);
|
||||
return false;
|
||||
}
|
||||
|
||||
synchronized (mService.mGlobalLock) {
|
||||
mService.mAtmService.setFocusedTask(win.getTask().mTaskId);
|
||||
}
|
||||
return true;
|
||||
@@ -115,25 +134,37 @@ class TaskPositioningController {
|
||||
|
||||
void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
|
||||
mService.mH.post(() -> {
|
||||
Task task;
|
||||
CompletableFuture<Boolean> startPositioningLockedFuture;
|
||||
synchronized (mService.mGlobalLock) {
|
||||
final Task task = displayContent.findTaskForResizePoint(x, y);
|
||||
if (task != null) {
|
||||
if (!task.isResizeable()) {
|
||||
// The task is not resizable, so don't do anything when the user drags the
|
||||
// the resize handles.
|
||||
return;
|
||||
}
|
||||
if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
|
||||
task.preserveOrientationOnResize(), x, y)) {
|
||||
return;
|
||||
}
|
||||
mService.mAtmService.setFocusedTask(task.mTaskId);
|
||||
task = displayContent.findTaskForResizePoint(x, y);
|
||||
if (task == null || !task.isResizeable()) {
|
||||
// The task is not resizable, so don't do anything when the user drags the
|
||||
// the resize handles.
|
||||
return;
|
||||
}
|
||||
startPositioningLockedFuture =
|
||||
startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
|
||||
task.preserveOrientationOnResize(), x, y);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!startPositioningLockedFuture.get()) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Slog.e(TAG_WM, "Exception thrown while waiting for startPositionLocked future",
|
||||
exception);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mService.mGlobalLock) {
|
||||
mService.mAtmService.setFocusedTask(task.mTaskId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean startPositioningLocked(WindowState win, boolean resize,
|
||||
private CompletableFuture<Boolean> startPositioningLocked(WindowState win, boolean resize,
|
||||
boolean preserveOrientation, float startX, float startY) {
|
||||
if (DEBUG_TASK_POSITIONING)
|
||||
Slog.d(TAG_WM, "startPositioningLocked: "
|
||||
@@ -142,43 +173,48 @@ class TaskPositioningController {
|
||||
|
||||
if (win == null || win.mActivityRecord == null) {
|
||||
Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
|
||||
return false;
|
||||
return completedFuture(false);
|
||||
}
|
||||
if (win.mInputChannel == null) {
|
||||
Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
|
||||
+ " probably being removed");
|
||||
return false;
|
||||
return completedFuture(false);
|
||||
}
|
||||
|
||||
final DisplayContent displayContent = win.getDisplayContent();
|
||||
if (displayContent == null) {
|
||||
Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
|
||||
return false;
|
||||
return completedFuture(false);
|
||||
}
|
||||
mPositioningDisplay = displayContent;
|
||||
|
||||
mTaskPositioner = TaskPositioner.create(mService);
|
||||
mTaskPositioner.register(displayContent, win);
|
||||
return mTaskPositioner.register(displayContent, win).thenApply(unused -> {
|
||||
// The global lock is held by the callers of startPositioningLocked but released before
|
||||
// the async results are waited on. We must acquire the lock in this callback to ensure
|
||||
// thread safety.
|
||||
synchronized (mService.mGlobalLock) {
|
||||
// We need to grab the touch focus so that the touch events during the
|
||||
// resizing/scrolling are not sent to the app. 'win' is the main window
|
||||
// of the app, it may not have focus since there might be other windows
|
||||
// on top (eg. a dialog window).
|
||||
WindowState transferFocusFromWin = win;
|
||||
if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
|
||||
&& displayContent.mCurrentFocus.mActivityRecord == win.mActivityRecord) {
|
||||
transferFocusFromWin = displayContent.mCurrentFocus;
|
||||
}
|
||||
if (!mService.mInputManager.transferTouchFocus(
|
||||
transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
|
||||
false /* isDragDrop */)) {
|
||||
Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
|
||||
cleanUpTaskPositioner();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to grab the touch focus so that the touch events during the
|
||||
// resizing/scrolling are not sent to the app. 'win' is the main window
|
||||
// of the app, it may not have focus since there might be other windows
|
||||
// on top (eg. a dialog window).
|
||||
WindowState transferFocusFromWin = win;
|
||||
if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
|
||||
&& displayContent.mCurrentFocus.mActivityRecord == win.mActivityRecord) {
|
||||
transferFocusFromWin = displayContent.mCurrentFocus;
|
||||
}
|
||||
if (!mService.mInputManager.transferTouchFocus(
|
||||
transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
|
||||
false /* isDragDrop */)) {
|
||||
Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
|
||||
cleanUpTaskPositioner();
|
||||
return false;
|
||||
}
|
||||
|
||||
mTaskPositioner.startDrag(resize, preserveOrientation, startX, startY);
|
||||
return true;
|
||||
mTaskPositioner.startDrag(resize, preserveOrientation, startX, startY);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void finishTaskPositioning(IWindow window) {
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.android.server.policy.WindowManagerPolicy;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Window manager local system service interface.
|
||||
@@ -303,12 +304,13 @@ public abstract class WindowManagerInternal {
|
||||
* An interface to customize drag and drop behaviors.
|
||||
*/
|
||||
public interface IDragDropCallback {
|
||||
default boolean registerInputChannel(
|
||||
default CompletableFuture<Boolean> registerInputChannel(
|
||||
DragState state, Display display, InputManagerService service,
|
||||
InputChannel source) {
|
||||
state.register(display);
|
||||
return service.transferTouchFocus(source, state.getInputChannel(),
|
||||
true /* isDragDrop */);
|
||||
return state.register(display)
|
||||
.thenApply(unused ->
|
||||
service.transferTouchFocus(source, state.getInputChannel(),
|
||||
true /* isDragDrop */));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -344,6 +344,8 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -374,6 +376,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// proceding with safe mode detection.
|
||||
private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
|
||||
|
||||
private static final int SYNC_INPUT_TRANSACTIONS_TIMEOUT_MS = 5000;
|
||||
|
||||
// Poll interval in milliseconds for watching boot animation finished.
|
||||
// TODO(b/159045990) Migrate to SystemService.waitForState with dedicated thread.
|
||||
private static final int BOOT_ANIMATION_POLL_INTERVAL = 50;
|
||||
@@ -8442,7 +8446,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
displayContent.getInputMonitor().updateInputWindowsImmediately(t));
|
||||
}
|
||||
|
||||
t.syncInputWindows().apply();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
t.addWindowInfosReportedListener(countDownLatch::countDown).apply();
|
||||
countDownLatch.await(SYNC_INPUT_TRANSACTIONS_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException exception) {
|
||||
Slog.e(TAG_WM, "Exception thrown while waiting for window infos to be reported",
|
||||
exception);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.view.InputWindowHandle;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -37,8 +38,14 @@ import java.util.concurrent.Executor;
|
||||
* testing to avoid calls to native code.
|
||||
*/
|
||||
public class StubTransaction extends SurfaceControl.Transaction {
|
||||
|
||||
private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
for (Runnable listener : mWindowInfosReportedListeners) {
|
||||
listener.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,6 +54,7 @@ public class StubTransaction extends SurfaceControl.Transaction {
|
||||
|
||||
@Override
|
||||
public void apply(boolean sync) {
|
||||
apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,11 +242,6 @@ public class StubTransaction extends SurfaceControl.Transaction {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl.Transaction syncInputWindows() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl.Transaction setColorSpaceAgnostic(SurfaceControl sc, boolean agnostic) {
|
||||
return this;
|
||||
@@ -299,4 +302,10 @@ public class StubTransaction extends SurfaceControl.Transaction {
|
||||
boolean isTrustedOverlay) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl.Transaction addWindowInfosReportedListener(@NonNull Runnable listener) {
|
||||
mWindowInfosReportedListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user