Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea66a1e9 authored by Patrick Williams's avatar Patrick Williams
Browse files

Replace syncInputWindows with addWindowInfosReportedListener

Bug: 222421815
Change-Id: Ia76481daa1ec2684890eb3ae58fafa148424843b
Test: DragDropControllerTests
parent 1475e5f3
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -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;
        }

+55 −11
Original line number Diff line number Diff line
@@ -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");
+47 −30
Original line number Diff line number Diff line
@@ -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,10 +162,41 @@ 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)) {
                                callingWin.mInputChannel);
                    } else {
                        // Skip surface logic for a drag triggered by an AccessibilityAction
                        mDragState.broadcastDragStartedLocked(touchX, touchY);

                        // Timeout for the user to drop the content
                        sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, callingWin.mClient.asBinder(),
                                getAccessibilityManager().getRecommendedTimeoutMillis(
                                        A11Y_DRAG_TIMEOUT_DEFAULT_MS,
                                        AccessibilityManager.FLAG_CONTENT_CONTROLS));

                        return dragToken;
                    }
                } finally {
                    if (surface != null) {
                        surface.release();
                    }
                }
            }

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

@@ -185,24 +220,6 @@ class DragDropController {
                if (SHOW_LIGHT_TRANSACTIONS) {
                    Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
                }
                    } else {
                        // Skip surface logic for a drag triggered by an AccessibilityAction
                        mDragState.broadcastDragStartedLocked(touchX, touchY);

                        // Timeout for the user to drop the content
                        sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, callingWin.mClient.asBinder(),
                                getAccessibilityManager().getRecommendedTimeoutMillis(
                                        A11Y_DRAG_TIMEOUT_DEFAULT_MS,
                                        AccessibilityManager.FLAG_CONTENT_CONTROLS));
                    }
                } finally {
                    if (surface != null) {
                        surface.release();
                    }
                    if (mDragState != null && !mDragState.isInProgress()) {
                        mDragState.closeLocked();
                    }
                }
            }
            return dragToken;    // success!
        } finally {
+17 −7
Original line number Diff line number Diff line
@@ -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();
        }
    }

+7 −7
Original line number Diff line number Diff line
@@ -147,13 +147,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();
        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);
        });
                mService.mInputManager.onDisplayRemoved(mDisplayId))
            .apply();
        mDisplayRemoved = true;
    }

Loading