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

Commit 2ef7e399 authored by Xin Li's avatar Xin Li
Browse files

Merge ab/6749736 in stage.

Bug: 167233921
Merged-In: Id9c756552c08d7690b99987dafadc13448a0c236
Change-Id: I93903c258f834a9e9537b88882d77a6660482638
parents aef9c20a 0581f5b0
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -156,8 +156,7 @@
        <provider
            android:name="com.android.launcher3.graphics.GridOptionsProvider"
            android:authorities="${packageName}.grid_control"
            android:exported="true"
            android:enabled="false" />
            android:exported="true" />

        <!--
        The settings activity. To extend point settings_fragment_name to appropriate fragment class
+4 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TransformParams;
@@ -61,7 +62,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
    private static final String TAG = "BaseSwipeUpHandler";

    protected final BaseActivityInterface<?, T> mActivityInterface;
    protected final InputConsumerController mInputConsumer;
    protected final InputConsumerProxy mInputConsumerProxy;

    protected final ActivityInitListener mActivityInitListener;

@@ -87,7 +88,8 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
        super(context, deviceState, gestureState, new TransformParams());
        mActivityInterface = gestureState.getActivityInterface();
        mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
        mInputConsumer = inputConsumer;
        mInputConsumerProxy =
                new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler);
    }

    /**
+3 −4
Original line number Diff line number Diff line
@@ -850,11 +850,9 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
            }
        }

        if (endTarget.isLauncher && mRecentsAnimationController != null) {
            mRecentsAnimationController.enableInputProxy(mInputConsumer,
                    this::createNewInputProxyHandler);
        if (endTarget.isLauncher) {
            mInputConsumerProxy.enable();
        }

        if (endTarget == HOME) {
            setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
            duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
@@ -1181,6 +1179,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
    }

    private void invalidateHandler() {
        mInputConsumerProxy.destroy();
        endRunningWindowAnim(false /* cancel */);

        if (mGestureEndCallback != null) {
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.quickstep.util;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;

import android.util.Log;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;

import com.android.quickstep.InputConsumer;
import com.android.systemui.shared.system.InputConsumerController;

import java.util.function.Supplier;

/**
 * Utility class which manages proxying input events from {@link InputConsumerController}
 * to an {@link InputConsumer}
 */
public class InputConsumerProxy {

    private static final String TAG = "InputConsumerProxy";

    private final InputConsumerController mInputConsumerController;
    private final Supplier<InputConsumer> mConsumerSupplier;

    // The consumer is created lazily on demand.
    private InputConsumer mInputConsumer;

    private boolean mDestroyed = false;
    private boolean mTouchInProgress = false;
    private boolean mDestroyPending = false;

    public InputConsumerProxy(InputConsumerController inputConsumerController,
            Supplier<InputConsumer> consumerSupplier) {
        mInputConsumerController = inputConsumerController;
        mConsumerSupplier = consumerSupplier;
    }

    public void enable() {
        if (mDestroyed) {
            return;
        }
        mInputConsumerController.setInputListener(this::onInputConsumerEvent);
    }

    private boolean onInputConsumerEvent(InputEvent ev) {
        if (ev instanceof MotionEvent) {
            onInputConsumerMotionEvent((MotionEvent) ev);
        } else if (ev instanceof KeyEvent) {
            if (mInputConsumer == null) {
                mInputConsumer = mConsumerSupplier.get();
            }
            mInputConsumer.onKeyEvent((KeyEvent) ev);
            return true;
        }
        return false;
    }

    private boolean onInputConsumerMotionEvent(MotionEvent ev) {
        int action = ev.getAction();

        // Just to be safe, verify that ACTION_DOWN comes before any other action,
        // and ignore any ACTION_DOWN after the first one (though that should not happen).
        if (!mTouchInProgress && action != ACTION_DOWN) {
            Log.w(TAG, "Received non-down motion before down motion: " + action);
            return false;
        }
        if (mTouchInProgress && action == ACTION_DOWN) {
            Log.w(TAG, "Received down motion while touch was already in progress");
            return false;
        }

        if (action == ACTION_DOWN) {
            mTouchInProgress = true;
            if (mInputConsumer == null) {
                mInputConsumer = mConsumerSupplier.get();
            }
        } else if (action == ACTION_CANCEL || action == ACTION_UP) {
            // Finish any pending actions
            mTouchInProgress = false;
            if (mDestroyPending) {
                destroy();
            }
        }
        if (mInputConsumer != null) {
            mInputConsumer.onMotionEvent(ev);
        }

        return true;
    }

    public void destroy() {
        if (mTouchInProgress) {
            mDestroyPending = true;
            return;
        }
        mDestroyPending = false;
        mDestroyed = true;
        mInputConsumerController.setInputListener(null);
    }
}
+2 −101
Original line number Diff line number Diff line
@@ -15,49 +15,30 @@
 */
package com.android.quickstep;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;

import android.os.SystemClock;
import android.util.Log;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.annotation.UiThread;

import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * Wrapper around RecentsAnimationControllerCompat to help with some synchronization
 */
public class RecentsAnimationController {

    private static final String TAG = "RecentsAnimationController";

    private final RecentsAnimationControllerCompat mController;
    private final Consumer<RecentsAnimationController> mOnFinishedListener;
    private final boolean mAllowMinimizeSplitScreen;

    private InputConsumerController mInputConsumerController;
    private Supplier<InputConsumer> mInputProxySupplier;
    private InputConsumer mInputConsumer;
    private boolean mUseLauncherSysBarFlags = false;
    private boolean mSplitScreenMinimized = false;
    private boolean mTouchInProgress;
    private boolean mDisableInputProxyPending;

    public RecentsAnimationController(RecentsAnimationControllerCompat controller,
            boolean allowMinimizeSplitScreen,
@@ -136,12 +117,12 @@ public class RecentsAnimationController {

    @UiThread
    public void finishAnimationToHome() {
        finishAndDisableInputProxy(true /* toRecents */, null, false /* sendUserLeaveHint */);
        finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
    }

    @UiThread
    public void finishAnimationToApp() {
        finishAndDisableInputProxy(false /* toRecents */, null, false /* sendUserLeaveHint */);
        finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
    }

    /** See {@link #finish(boolean, Runnable, boolean)} */
@@ -160,18 +141,6 @@ public class RecentsAnimationController {
    @UiThread
    public void finish(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) {
        Preconditions.assertUIThread();
        if (toRecents && mTouchInProgress) {
            // Finish the controller as requested, but don't disable input proxy yet.
            mDisableInputProxyPending = true;
            finishController(toRecents, onFinishComplete, sendUserLeaveHint);
        } else {
            finishAndDisableInputProxy(toRecents, onFinishComplete, sendUserLeaveHint);
        }
    }

    private void finishAndDisableInputProxy(boolean toRecents, Runnable onFinishComplete,
            boolean sendUserLeaveHint) {
        disableInputProxy();
        finishController(toRecents, onFinishComplete, sendUserLeaveHint);
    }

@@ -179,7 +148,6 @@ public class RecentsAnimationController {
    public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
        mOnFinishedListener.accept(this);
        UI_HELPER_EXECUTOR.execute(() -> {
            mController.setInputConsumerEnabled(false);
            mController.finish(toRecents, sendUserLeaveHint);
            if (callback != null) {
                MAIN_EXECUTOR.execute(callback);
@@ -197,75 +165,8 @@ public class RecentsAnimationController {
        });
    }

    public void enableInputProxy(InputConsumerController inputConsumerController,
            Supplier<InputConsumer> inputProxySupplier) {
        mInputProxySupplier = inputProxySupplier;
        mInputConsumerController = inputConsumerController;
        mInputConsumerController.setInputListener(this::onInputConsumerEvent);
    }

    /** @return wrapper controller. */
    public RecentsAnimationControllerCompat getController() {
        return mController;
    }

    private void disableInputProxy() {
        if (mInputConsumer != null && mTouchInProgress) {
            long now = SystemClock.uptimeMillis();
            MotionEvent dummyCancel = MotionEvent.obtain(now,  now, ACTION_CANCEL, 0, 0, 0);
            mInputConsumer.onMotionEvent(dummyCancel);
            dummyCancel.recycle();
        }
        if (mInputConsumerController != null) {
            mInputConsumerController.setInputListener(null);
        }
        mInputProxySupplier = null;
    }

    private boolean onInputConsumerEvent(InputEvent ev) {
        if (ev instanceof MotionEvent) {
            onInputConsumerMotionEvent((MotionEvent) ev);
        } else if (ev instanceof KeyEvent) {
            if (mInputConsumer == null) {
                mInputConsumer = mInputProxySupplier.get();
            }
            mInputConsumer.onKeyEvent((KeyEvent) ev);
            return true;
        }
        return false;
    }

    private boolean onInputConsumerMotionEvent(MotionEvent ev) {
        int action = ev.getAction();

        // Just to be safe, verify that ACTION_DOWN comes before any other action,
        // and ignore any ACTION_DOWN after the first one (though that should not happen).
        if (!mTouchInProgress && action != ACTION_DOWN) {
            Log.w(TAG, "Received non-down motion before down motion: " + action);
            return false;
        }
        if (mTouchInProgress && action == ACTION_DOWN) {
            Log.w(TAG, "Received down motion while touch was already in progress");
            return false;
        }

        if (action == ACTION_DOWN) {
            mTouchInProgress = true;
            if (mInputConsumer == null) {
                mInputConsumer = mInputProxySupplier.get();
            }
        } else if (action == ACTION_CANCEL || action == ACTION_UP) {
            // Finish any pending actions
            mTouchInProgress = false;
            if (mDisableInputProxyPending) {
                mDisableInputProxyPending = false;
                disableInputProxy();
            }
        }
        if (mInputConsumer != null) {
            mInputConsumer.onMotionEvent(ev);
        }

        return true;
    }
}
Loading