1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.wm.shell.back; 18 19 import android.os.SystemProperties; 20 import android.view.RemoteAnimationTarget; 21 import android.window.BackEvent; 22 import android.window.BackMotionEvent; 23 24 /** 25 * Helper class to record the touch location for gesture and generate back events. 26 */ 27 class TouchTracker { 28 private static final String PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP = 29 "persist.wm.debug.predictive_back_progress_threshold"; 30 private static final int PROGRESS_THRESHOLD = SystemProperties 31 .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1); 32 private float mProgressThreshold; 33 /** 34 * Location of the latest touch event 35 */ 36 private float mLatestTouchX; 37 private float mLatestTouchY; 38 private boolean mTriggerBack; 39 40 /** 41 * Location of the initial touch event of the back gesture. 42 */ 43 private float mInitTouchX; 44 private float mInitTouchY; 45 private float mStartThresholdX; 46 private int mSwipeEdge; 47 private boolean mCancelled; 48 update(float touchX, float touchY)49 void update(float touchX, float touchY) { 50 /** 51 * If back was previously cancelled but the user has started swiping in the forward 52 * direction again, restart back. 53 */ 54 if (mCancelled && ((touchX > mLatestTouchX && mSwipeEdge == BackEvent.EDGE_LEFT) 55 || touchX < mLatestTouchX && mSwipeEdge == BackEvent.EDGE_RIGHT)) { 56 mCancelled = false; 57 mStartThresholdX = touchX; 58 } 59 mLatestTouchX = touchX; 60 mLatestTouchY = touchY; 61 } 62 setTriggerBack(boolean triggerBack)63 void setTriggerBack(boolean triggerBack) { 64 if (mTriggerBack != triggerBack && !triggerBack) { 65 mCancelled = true; 66 } 67 mTriggerBack = triggerBack; 68 } 69 setGestureStartLocation(float touchX, float touchY, int swipeEdge)70 void setGestureStartLocation(float touchX, float touchY, int swipeEdge) { 71 mInitTouchX = touchX; 72 mInitTouchY = touchY; 73 mSwipeEdge = swipeEdge; 74 mStartThresholdX = mInitTouchX; 75 } 76 reset()77 void reset() { 78 mInitTouchX = 0; 79 mInitTouchY = 0; 80 mStartThresholdX = 0; 81 mCancelled = false; 82 mTriggerBack = false; 83 mSwipeEdge = BackEvent.EDGE_LEFT; 84 } 85 createStartEvent(RemoteAnimationTarget target)86 BackMotionEvent createStartEvent(RemoteAnimationTarget target) { 87 return new BackMotionEvent(mInitTouchX, mInitTouchY, 0, mSwipeEdge, target); 88 } 89 createProgressEvent()90 BackMotionEvent createProgressEvent() { 91 float progressThreshold = PROGRESS_THRESHOLD >= 0 92 ? PROGRESS_THRESHOLD : mProgressThreshold; 93 progressThreshold = progressThreshold == 0 ? 1 : progressThreshold; 94 float progress = 0; 95 // Progress is always 0 when back is cancelled and not restarted. 96 if (!mCancelled) { 97 // If back is committed, progress is the distance between the last and first touch 98 // point, divided by the max drag distance. Otherwise, it's the distance between 99 // the last touch point and the starting threshold, divided by max drag distance. 100 // The starting threshold is initially the first touch location, and updated to 101 // the location everytime back is restarted after being cancelled. 102 float startX = mTriggerBack ? mInitTouchX : mStartThresholdX; 103 float deltaX = Math.max( 104 mSwipeEdge == BackEvent.EDGE_LEFT 105 ? mLatestTouchX - startX 106 : startX - mLatestTouchX, 107 0); 108 progress = Math.min(Math.max(deltaX / progressThreshold, 0), 1); 109 } 110 return createProgressEvent(progress); 111 } 112 createProgressEvent(float progress)113 BackMotionEvent createProgressEvent(float progress) { 114 return new BackMotionEvent(mLatestTouchX, mLatestTouchY, progress, mSwipeEdge, null); 115 } 116 setProgressThreshold(float progressThreshold)117 public void setProgressThreshold(float progressThreshold) { 118 mProgressThreshold = progressThreshold; 119 } 120 } 121