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

Commit 0607cf03 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Forwarding touch events from TouchInteractionService to Launcher

when launcher window is visible

Change-Id: I418994c2e2a5559c28c36875ac7aff589a15fac5
parent 635329a5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks {

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mSnapshotView = findViewById(R.id.snapshot);
        mIconView = findViewById(R.id.icon);
    }
+119 −19
Original line number Diff line number Diff line
@@ -15,8 +15,15 @@
 */
package com.android.quickstep;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;

import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.Service;
@@ -29,6 +36,7 @@ import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -37,9 +45,12 @@ import android.view.Choreographer;
import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;

import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.TraceHelper;
@@ -51,9 +62,12 @@ import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;

import java.util.function.Consumer;

/**
 * Service connected by system-UI for handling touch interaction.
 */
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {

    private static final String TAG = "TouchInteractionService";
@@ -73,6 +87,10 @@ public class TouchInteractionService extends Service {
        }
    };

    private final Consumer<MotionEvent> mOtherActivityTouchConsumer
            = this::handleTouchDownOnOtherActivity;
    private final Consumer<MotionEvent> mNoOpTouchConsumer = (ev) -> {};

    private ActivityManagerWrapper mAM;
    private RunningTaskInfo mRunningTask;
    private Intent mHomeIntent;
@@ -80,8 +98,6 @@ public class TouchInteractionService extends Service {
    private MotionEventQueue mEventQueue;
    private MainThreadExecutor mMainThreadExecutor;

    private int mDisplayRotation;
    private final Point mDisplaySize = new Point();
    private final PointF mDownPos = new PointF();
    private final PointF mLastPos = new PointF();
    private int mActivePointerId = INVALID_POINTER_ID;
@@ -90,6 +106,7 @@ public class TouchInteractionService extends Service {
    private NavBarSwipeInteractionHandler mInteractionHandler;

    private ISystemUiProxy mISystemUiProxy;
    private Consumer<MotionEvent> mCurrentConsumer = mNoOpTouchConsumer;

    @Override
    public void onCreate() {
@@ -127,25 +144,31 @@ public class TouchInteractionService extends Service {
    }

    private void handleMotionEvent(MotionEvent ev) {
        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN && mVelocityTracker == null) {
        if (ev.getActionMasked() == ACTION_DOWN) {
            mRunningTask = mAM.getRunningTask();

            if (mRunningTask == null) {
                mCurrentConsumer = mNoOpTouchConsumer;
            } else if (mRunningTask.topActivity.equals(mLauncher)) {
                mCurrentConsumer = getLauncherConsumer();
            } else {
                mCurrentConsumer = mOtherActivityTouchConsumer;
            }
        }
        mCurrentConsumer.accept(ev);
    }

    private void handleTouchDownOnOtherActivity(MotionEvent ev) {
        if (ev.getActionMasked() != ACTION_DOWN && mVelocityTracker == null) {
            return;
        }
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
            case ACTION_DOWN: {
                TraceHelper.beginSection("TouchInt");
                mActivePointerId = ev.getPointerId(0);
                mDownPos.set(ev.getX(), ev.getY());
                mLastPos.set(mDownPos);
                mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
                Display display = getSystemService(WindowManager.class).getDefaultDisplay();
                display.getRealSize(mDisplaySize);
                mDisplayRotation = display.getRotation();

                mRunningTask = mAM.getRunningTask();
                if (mRunningTask == null || mRunningTask.topActivity.equals(mLauncher)) {
                    // TODO: We could drive all-apps in this case. For now just ignore swipe.
                    break;
                }

                if (mVelocityTracker == null) {
                    mVelocityTracker = VelocityTracker.obtain();
@@ -159,7 +182,7 @@ public class TouchInteractionService extends Service {
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {
            case ACTION_POINTER_UP: {
                int ptrIdx = ev.getActionIndex();
                int ptrId = ev.getPointerId(ptrIdx);
                if (ptrId == mActivePointerId) {
@@ -173,7 +196,7 @@ public class TouchInteractionService extends Service {
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {
            case ACTION_MOVE: {
                int pointerIndex = ev.findPointerIndex(mActivePointerId);
                if (pointerIndex == INVALID_POINTER_ID) {
                    break;
@@ -192,17 +215,19 @@ public class TouchInteractionService extends Service {
                }
                break;
            }
            case MotionEvent.ACTION_CANCEL:
            case ACTION_CANCEL:
                // TODO: Should be different than ACTION_UP
            case MotionEvent.ACTION_UP: {
            case ACTION_UP: {
                TraceHelper.endSection("TouchInt");

                endInteraction();
                mCurrentConsumer = mNoOpTouchConsumer;
                break;
            }
        }
    }


    private void startTouchTracking() {
        // Create the shared handler
        final NavBarSwipeInteractionHandler handler =
@@ -260,9 +285,12 @@ public class TouchInteractionService extends Service {

        TraceHelper.beginSection("TaskSnapshot");
        // TODO: We are using some hardcoded layers for now, to best approximate the activity layers
        Point displaySize = new Point();
        Display display = getSystemService(WindowManager.class).getDefaultDisplay();
        display.getRealSize(displaySize);
        try {
            return mISystemUiProxy.screenshot(new Rect(), mDisplaySize.x, mDisplaySize.y, 0, 100000,
                    false, mDisplayRotation).toBitmap();
            return mISystemUiProxy.screenshot(new Rect(), displaySize.x, displaySize.y, 0, 100000,
                    false, display.getRotation()).toBitmap();
        } catch (RemoteException e) {
            Log.e(TAG, "Error capturing snapshot", e);
            return null;
@@ -270,4 +298,76 @@ public class TouchInteractionService extends Service {
            TraceHelper.endSection("TaskSnapshot");
        }
    }

    private Consumer<MotionEvent> getLauncherConsumer() {

        Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
        if (launcher == null) {
            return mNoOpTouchConsumer;
        }

        View target = launcher.getDragLayer();
        if (!target.getWindowId().isFocused()) {
            return mNoOpTouchConsumer;
        }
        return new LauncherTouchConsumer(target);
    }

    private class LauncherTouchConsumer implements Consumer<MotionEvent> {

        private final View mTarget;
        private final int[] mLocationOnScreen = new int[2];

        private boolean mTrackingStarted = false;

        LauncherTouchConsumer(View target) {
            mTarget = target;
        }

        @Override
        public void accept(MotionEvent ev) {
            int action = ev.getActionMasked();
            if (action == ACTION_DOWN) {
                mTrackingStarted = false;
                mDownPos.set(ev.getX(), ev.getY());
                mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
            } else if (!mTrackingStarted) {
                switch (action) {
                    case ACTION_POINTER_UP:
                    case ACTION_POINTER_DOWN:
                        if (!mTrackingStarted) {
                            mCurrentConsumer = mNoOpTouchConsumer;
                        }
                        break;
                    case ACTION_MOVE: {
                        float displacement = ev.getY() - mDownPos.y;
                        if (Math.abs(displacement) >= mTouchSlop) {
                            mTrackingStarted = true;
                            mTarget.getLocationOnScreen(mLocationOnScreen);

                            // Send a down event only when mTouchSlop is crossed.
                            MotionEvent down = MotionEvent.obtain(ev);
                            down.setAction(ACTION_DOWN);
                            sendEvent(down);
                            down.recycle();
                        }
                    }
                }
            }

            if (mTrackingStarted) {
                sendEvent(ev);
            }

            if (action == ACTION_UP || action == ACTION_CANCEL) {
                mCurrentConsumer = mNoOpTouchConsumer;
            }
        }

        private void sendEvent(MotionEvent ev) {
            ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
            mTarget.dispatchTouchEvent(ev);
            ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
        }
    }
}