mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 16:26:47 +00:00
Merge changes I562abc6c,I7a48d960,I0916f969 into tm-qpr-dev am: 7fb96a5305
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19517498 Change-Id: I21769aa2d541176fb63faceb55043dfccee1a693 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
committed by
Automerger Merge Worker
commit
2ed4c84e68
@@ -94,6 +94,7 @@ import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
|
||||
import com.android.quickstep.util.ProtoTracer;
|
||||
import com.android.quickstep.util.ProxyScreenStatusProvider;
|
||||
import com.android.quickstep.util.SplitScreenBounds;
|
||||
@@ -126,6 +127,9 @@ import java.util.function.Function;
|
||||
public class TouchInteractionService extends Service
|
||||
implements ProtoTraceable<LauncherTraceProto.Builder> {
|
||||
|
||||
private static final String SUBSTRING_PREFIX = "; ";
|
||||
private static final String NEWLINE_PREFIX = "\n\t\t\t-> ";
|
||||
|
||||
private static final String TAG = "TouchInteractionService";
|
||||
|
||||
private static final boolean BUBBLES_HOME_GESTURE_ENABLED =
|
||||
@@ -619,8 +623,6 @@ public class TouchInteractionService extends Service
|
||||
mConsumer.onConsumerAboutToBeSwitched();
|
||||
mGestureState = newGestureState;
|
||||
mConsumer = newConsumer(prevGestureState, mGestureState, event);
|
||||
|
||||
ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
|
||||
mUncheckedConsumer = mConsumer;
|
||||
} else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
|
||||
&& mDeviceState.canTriggerAssistantAction(event)) {
|
||||
@@ -628,8 +630,7 @@ public class TouchInteractionService extends Service
|
||||
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
|
||||
// should not interrupt it. QuickSwitch assumes that interruption can only
|
||||
// happen if the next gesture is also quick switch.
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(
|
||||
InputConsumer.NO_OP, mGestureState, event);
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
|
||||
} else if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
// Consume gesture event for triggering one handed feature.
|
||||
mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
|
||||
@@ -676,17 +677,31 @@ public class TouchInteractionService extends Service
|
||||
ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
|
||||
}
|
||||
|
||||
private InputConsumer tryCreateAssistantInputConsumer(InputConsumer base,
|
||||
private InputConsumer tryCreateAssistantInputConsumer(
|
||||
GestureState gestureState, MotionEvent motionEvent) {
|
||||
return mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())
|
||||
? base
|
||||
: new AssistantInputConsumer(this, gestureState, base, mInputMonitorCompat,
|
||||
mDeviceState, motionEvent);
|
||||
return tryCreateAssistantInputConsumer(
|
||||
InputConsumer.NO_OP, gestureState, motionEvent, CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
private InputConsumer tryCreateAssistantInputConsumer(
|
||||
InputConsumer base,
|
||||
GestureState gestureState,
|
||||
MotionEvent motionEvent,
|
||||
CompoundString reasonString) {
|
||||
if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("is gesture-blocked task, using base input consumer");
|
||||
return base;
|
||||
} else {
|
||||
reasonString.append(SUBSTRING_PREFIX).append("using AssistantInputConsumer");
|
||||
return new AssistantInputConsumer(
|
||||
this, gestureState, base, mInputMonitorCompat, mDeviceState, motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public GestureState createGestureState(GestureState previousGestureState) {
|
||||
GestureState gestureState = new GestureState(mOverviewComponentObserver,
|
||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||
ActiveGestureLog.INSTANCE.incrementLogId());
|
||||
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
|
||||
gestureState.updateRunningTask(previousGestureState.getRunningTask());
|
||||
gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId());
|
||||
@@ -699,50 +714,88 @@ public class TouchInteractionService extends Service
|
||||
return gestureState;
|
||||
}
|
||||
|
||||
private InputConsumer newConsumer(GestureState previousGestureState,
|
||||
GestureState newGestureState, MotionEvent event) {
|
||||
private InputConsumer newConsumer(
|
||||
GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
|
||||
AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
|
||||
if (progressProxy != null) {
|
||||
return new ProgressDelegateInputConsumer(this, mTaskAnimationManager,
|
||||
mGestureState, mInputMonitorCompat, progressProxy);
|
||||
InputConsumer consumer = new ProgressDelegateInputConsumer(
|
||||
this, mTaskAnimationManager, mGestureState, mInputMonitorCompat, progressProxy);
|
||||
|
||||
logInputConsumerSelectionReason(consumer, newCompoundString(
|
||||
"mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"));
|
||||
|
||||
return consumer;
|
||||
}
|
||||
|
||||
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
|
||||
|
||||
if (!mDeviceState.isUserUnlocked()) {
|
||||
CompoundString reasonString = newCompoundString("device locked");
|
||||
InputConsumer consumer;
|
||||
if (canStartSystemGesture) {
|
||||
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
|
||||
// launched while device is locked even after exiting direct boot mode (e.g. camera).
|
||||
return createDeviceLockedInputConsumer(newGestureState);
|
||||
consumer = createDeviceLockedInputConsumer(
|
||||
newGestureState, reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("can start system gesture"));
|
||||
} else {
|
||||
return getDefaultInputConsumer();
|
||||
consumer = getDefaultInputConsumer(
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("cannot start system gesture"));
|
||||
}
|
||||
logInputConsumerSelectionReason(consumer, reasonString);
|
||||
return consumer;
|
||||
}
|
||||
|
||||
CompoundString reasonString;
|
||||
InputConsumer base;
|
||||
// When there is an existing recents animation running, bypass systemState check as this is
|
||||
// a followup gesture and the first gesture started in a valid system state.
|
||||
InputConsumer base = canStartSystemGesture
|
||||
|| previousGestureState.isRecentsAnimationRunning()
|
||||
? newBaseConsumer(previousGestureState, newGestureState, event)
|
||||
: getDefaultInputConsumer();
|
||||
if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning()) {
|
||||
reasonString = newCompoundString(canStartSystemGesture
|
||||
? "can start system gesture" : "recents animation was running")
|
||||
.append(", trying to use base consumer");
|
||||
base = newBaseConsumer(previousGestureState, newGestureState, event, reasonString);
|
||||
} else {
|
||||
reasonString = newCompoundString(
|
||||
"cannot start system gesture and recents animation was not running")
|
||||
.append(", trying to use default input consumer");
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
if (mDeviceState.isGesturalNavMode()) {
|
||||
handleOrientationSetup(base);
|
||||
}
|
||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||
String reasonPrefix = "device is in gesture navigation mode";
|
||||
if (mDeviceState.canTriggerAssistantAction(event)) {
|
||||
base = tryCreateAssistantInputConsumer(base, newGestureState, event);
|
||||
reasonString.append(NEWLINE_PREFIX)
|
||||
.append(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("gesture can trigger the assistant")
|
||||
.append(", trying to use assistant input consumer");
|
||||
base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString);
|
||||
}
|
||||
|
||||
// If Taskbar is present, we listen for long press to unstash it.
|
||||
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
|
||||
if (tac != null) {
|
||||
reasonString.append(NEWLINE_PREFIX)
|
||||
.append(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("TaskbarActivityContext != null, using TaskbarStashInputConsumer");
|
||||
base = new TaskbarStashInputConsumer(this, base, mInputMonitorCompat, tac);
|
||||
}
|
||||
|
||||
if (mDeviceState.isBubblesExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("bubbles expanded");
|
||||
if (BUBBLES_HOME_GESTURE_ENABLED) {
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("bubbles can handle the home gesture")
|
||||
.append(", trying to use default input consumer");
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer();
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
} else {
|
||||
// If Bubbles is expanded, use the overlay input consumer, which will close
|
||||
// Bubbles instead of going all the way home when a swipe up is detected.
|
||||
@@ -750,6 +803,9 @@ public class TouchInteractionService extends Service
|
||||
// expanded in the back. Make sure swipe up is not passed to bubbles in this
|
||||
// case.
|
||||
if (!mDeviceState.isNotificationPanelExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("using SysUiOverlayInputConsumer");
|
||||
base = new SysUiOverlayInputConsumer(
|
||||
getBaseContext(), mDeviceState, mInputMonitorCompat);
|
||||
}
|
||||
@@ -757,6 +813,9 @@ public class TouchInteractionService extends Service
|
||||
}
|
||||
|
||||
if (mDeviceState.isSystemUiDialogShowing()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("system dialog is showing, using SysUiOverlayInputConsumer");
|
||||
base = new SysUiOverlayInputConsumer(
|
||||
getBaseContext(), mDeviceState, mInputMonitorCompat);
|
||||
}
|
||||
@@ -764,44 +823,91 @@ public class TouchInteractionService extends Service
|
||||
|
||||
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("screen pinning is active, using ScreenPinnedInputConsumer");
|
||||
// Note: we only allow accessibility to wrap this, and it replaces the previous
|
||||
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
|
||||
base = new ScreenPinnedInputConsumer(this, newGestureState);
|
||||
}
|
||||
|
||||
if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
base = new OneHandedModeInputConsumer(this, mDeviceState, base,
|
||||
mInputMonitorCompat);
|
||||
reasonString.append(NEWLINE_PREFIX)
|
||||
.append(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("gesture can trigger one handed mode")
|
||||
.append(", using OneHandedModeInputConsumer");
|
||||
base = new OneHandedModeInputConsumer(
|
||||
this, mDeviceState, base, mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if (mDeviceState.isAccessibilityMenuAvailable()) {
|
||||
base = new AccessibilityInputConsumer(this, mDeviceState, base,
|
||||
mInputMonitorCompat);
|
||||
reasonString.append(NEWLINE_PREFIX)
|
||||
.append(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("accessibility menu is available")
|
||||
.append(", using AccessibilityInputConsumer");
|
||||
base = new AccessibilityInputConsumer(
|
||||
this, mDeviceState, base, mInputMonitorCompat);
|
||||
}
|
||||
} else {
|
||||
String reasonPrefix = "device is not in gesture navigation mode";
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
base = getDefaultInputConsumer();
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("screen pinning is active, trying to use default input consumer");
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
|
||||
if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
base = new OneHandedModeInputConsumer(this, mDeviceState, base,
|
||||
mInputMonitorCompat);
|
||||
reasonString.append(NEWLINE_PREFIX)
|
||||
.append(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("gesture can trigger one handed mode")
|
||||
.append(", using OneHandedModeInputConsumer");
|
||||
base = new OneHandedModeInputConsumer(
|
||||
this, mDeviceState, base, mInputMonitorCompat);
|
||||
}
|
||||
}
|
||||
logInputConsumerSelectionReason(base, reasonString);
|
||||
return base;
|
||||
}
|
||||
|
||||
private CompoundString newCompoundString(String substring) {
|
||||
return new CompoundString(NEWLINE_PREFIX).append(substring);
|
||||
}
|
||||
|
||||
private void logInputConsumerSelectionReason(
|
||||
InputConsumer consumer, CompoundString reasonString) {
|
||||
if (!FeatureFlags.ENABLE_INPUT_CONSUMER_REASON_LOGGING.get()) {
|
||||
ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + consumer.getName());
|
||||
return;
|
||||
}
|
||||
ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
|
||||
.append(consumer.getName())
|
||||
.append(". reason(s):")
|
||||
.append(reasonString));
|
||||
}
|
||||
|
||||
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
|
||||
baseInputConsumer.notifyOrientationSetup();
|
||||
}
|
||||
|
||||
private InputConsumer newBaseConsumer(GestureState previousGestureState,
|
||||
GestureState gestureState, MotionEvent event) {
|
||||
private InputConsumer newBaseConsumer(
|
||||
GestureState previousGestureState,
|
||||
GestureState gestureState,
|
||||
MotionEvent event,
|
||||
CompoundString reasonString) {
|
||||
if (mDeviceState.isKeyguardShowingOccluded()) {
|
||||
// This handles apps showing over the lockscreen (e.g. camera)
|
||||
return createDeviceLockedInputConsumer(gestureState);
|
||||
return createDeviceLockedInputConsumer(
|
||||
gestureState,
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("keyguard is showing occluded")
|
||||
.append(", trying to use device locked input consumer"));
|
||||
}
|
||||
|
||||
reasonString.append(SUBSTRING_PREFIX).append("keyguard is not showing occluded");
|
||||
// Use overview input consumer for sharesheets on top of home.
|
||||
boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
|
||||
&& gestureState.getRunningTask() != null
|
||||
@@ -815,23 +921,46 @@ public class TouchInteractionService extends Service
|
||||
forceOverviewInputConsumer = gestureState.getRunningTask().isHomeTask();
|
||||
}
|
||||
|
||||
boolean previousGestureAnimatedToLauncher =
|
||||
previousGestureState.isRunningAnimationToLauncher();
|
||||
// with shell-transitions, home is resumed during recents animation, so
|
||||
// explicitly check against recents animation too.
|
||||
boolean launcherResumedThroughShellTransition =
|
||||
gestureState.getActivityInterface().isResumed()
|
||||
&& !previousGestureState.isRecentsAnimationRunning();
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()
|
||||
&& gestureState.getActivityInterface().isInLiveTileMode()) {
|
||||
return createOverviewInputConsumer(
|
||||
previousGestureState, gestureState, event, forceOverviewInputConsumer);
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
forceOverviewInputConsumer,
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("is in live tile mode, trying to use overview input consumer"));
|
||||
} else if (gestureState.getRunningTask() == null) {
|
||||
return getDefaultInputConsumer();
|
||||
} else if (previousGestureState.isRunningAnimationToLauncher()
|
||||
|| (gestureState.getActivityInterface().isResumed()
|
||||
// with shell-transitions, home is resumed during recents animation, so
|
||||
// explicitly check against recents animation too.
|
||||
&& !previousGestureState.isRecentsAnimationRunning())
|
||||
return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("running task == null"));
|
||||
} else if (previousGestureAnimatedToLauncher
|
||||
|| launcherResumedThroughShellTransition
|
||||
|| forceOverviewInputConsumer) {
|
||||
return createOverviewInputConsumer(
|
||||
previousGestureState, gestureState, event, forceOverviewInputConsumer);
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
forceOverviewInputConsumer,
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append(previousGestureAnimatedToLauncher
|
||||
? "previous gesture animated to launcher"
|
||||
: (launcherResumedThroughShellTransition
|
||||
? "launcher resumed through a shell transition"
|
||||
: "forceOverviewInputConsumer == true"))
|
||||
.append(", trying to use overview input consumer"));
|
||||
} else if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
|
||||
return getDefaultInputConsumer();
|
||||
return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("is gesture-blocked task, trying to use default input consumer"));
|
||||
} else {
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("using OtherActivityInputConsumer");
|
||||
return createOtherActivityInputConsumer(gestureState, event);
|
||||
}
|
||||
}
|
||||
@@ -853,21 +982,34 @@ public class TouchInteractionService extends Service
|
||||
mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
|
||||
}
|
||||
|
||||
private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
|
||||
private InputConsumer createDeviceLockedInputConsumer(
|
||||
GestureState gestureState, CompoundString reasonString) {
|
||||
if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
|
||||
return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
|
||||
gestureState, mInputMonitorCompat);
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("device is in gesture nav mode and running task != null")
|
||||
.append(", using DeviceLockedInputConsumer");
|
||||
return new DeviceLockedInputConsumer(
|
||||
this, mDeviceState, mTaskAnimationManager, gestureState, mInputMonitorCompat);
|
||||
} else {
|
||||
return getDefaultInputConsumer();
|
||||
return getDefaultInputConsumer(reasonString
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append(mDeviceState.isFullyGesturalNavMode()
|
||||
? "running task == null" : "device is not in gesture nav mode")
|
||||
.append(", trying to use default input consumer"));
|
||||
}
|
||||
}
|
||||
|
||||
public InputConsumer createOverviewInputConsumer(GestureState previousGestureState,
|
||||
GestureState gestureState, MotionEvent event,
|
||||
boolean forceOverviewInputConsumer) {
|
||||
public InputConsumer createOverviewInputConsumer(
|
||||
GestureState previousGestureState,
|
||||
GestureState gestureState,
|
||||
MotionEvent event,
|
||||
boolean forceOverviewInputConsumer,
|
||||
CompoundString reasonString) {
|
||||
StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
|
||||
if (activity == null) {
|
||||
return getDefaultInputConsumer();
|
||||
return getDefaultInputConsumer(
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("activity == null, trying to use default input consumer"));
|
||||
}
|
||||
|
||||
if (activity.getRootView().hasWindowFocus()
|
||||
@@ -876,9 +1018,13 @@ public class TouchInteractionService extends Service
|
||||
&& forceOverviewInputConsumer)
|
||||
|| (ENABLE_QUICKSTEP_LIVE_TILE.get()
|
||||
&& gestureState.getActivityInterface().isInLiveTileMode())) {
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("overview should have focus, using OverviewInputConsumer");
|
||||
return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
|
||||
false /* startingInActivityBounds */);
|
||||
} else {
|
||||
reasonString.append(SUBSTRING_PREFIX).append(
|
||||
"overview shouldn't have focus, using OverviewWithoutFocusInputConsumer");
|
||||
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
|
||||
return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
|
||||
mInputMonitorCompat, disableHorizontalSwipe);
|
||||
@@ -906,13 +1052,21 @@ public class TouchInteractionService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull InputConsumer getDefaultInputConsumer() {
|
||||
return getDefaultInputConsumer(CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP.
|
||||
*/
|
||||
private @NonNull InputConsumer getDefaultInputConsumer() {
|
||||
private @NonNull InputConsumer getDefaultInputConsumer(@NonNull CompoundString reasonString) {
|
||||
if (mResetGestureInputConsumer != null) {
|
||||
reasonString.append(SUBSTRING_PREFIX).append(
|
||||
"mResetGestureInputConsumer initialized, using ResetGestureInputConsumer");
|
||||
return mResetGestureInputConsumer;
|
||||
} else {
|
||||
reasonString.append(SUBSTRING_PREFIX).append(
|
||||
"mResetGestureInputConsumer not initialized, using no-op input consumer");
|
||||
// mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
|
||||
// NO_OP until then (we never want these to be null).
|
||||
return InputConsumer.NO_OP;
|
||||
|
||||
@@ -15,15 +15,23 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.logging.EventLogArray;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A log to keep track of the active gesture.
|
||||
*/
|
||||
public class ActiveGestureLog extends EventLogArray {
|
||||
public class ActiveGestureLog {
|
||||
|
||||
private static final int MAX_GESTURES_TRACKED = 10;
|
||||
|
||||
public static final ActiveGestureLog INSTANCE = new ActiveGestureLog();
|
||||
|
||||
@@ -33,7 +41,238 @@ public class ActiveGestureLog extends EventLogArray {
|
||||
*/
|
||||
public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID";
|
||||
|
||||
private static final int TYPE_ONE_OFF = 0;
|
||||
private static final int TYPE_FLOAT = 1;
|
||||
private static final int TYPE_INTEGER = 2;
|
||||
private static final int TYPE_BOOL_TRUE = 3;
|
||||
private static final int TYPE_BOOL_FALSE = 4;
|
||||
private static final int TYPE_INPUT_CONSUMER = 5;
|
||||
|
||||
private final EventLog[] logs;
|
||||
private int nextIndex;
|
||||
private int mCurrentLogId = 100;
|
||||
|
||||
private ActiveGestureLog() {
|
||||
super("touch_interaction_log", 40);
|
||||
this.logs = new EventLog[MAX_GESTURES_TRACKED];
|
||||
this.nextIndex = 0;
|
||||
}
|
||||
|
||||
public void addLog(String event) {
|
||||
addLog(TYPE_ONE_OFF, event, 0, CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
public void addLog(String event, int extras) {
|
||||
addLog(TYPE_INTEGER, event, extras, CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
public void addLog(String event, boolean extras) {
|
||||
addLog(extras ? TYPE_BOOL_TRUE : TYPE_BOOL_FALSE, event, 0, CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
public void addLog(CompoundString compoundString) {
|
||||
addLog(TYPE_INPUT_CONSUMER, "", 0, compoundString);
|
||||
}
|
||||
|
||||
private void addLog(
|
||||
int type, String event, float extras, @NonNull CompoundString compoundString) {
|
||||
EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
|
||||
if (lastEventLog == null || mCurrentLogId != lastEventLog.logId) {
|
||||
EventLog eventLog = new EventLog(mCurrentLogId);
|
||||
EventEntry eventEntry = new EventEntry();
|
||||
|
||||
eventEntry.update(type, event, extras, compoundString);
|
||||
eventLog.eventEntries.add(eventEntry);
|
||||
logs[nextIndex] = eventLog;
|
||||
nextIndex = (nextIndex + 1) % logs.length;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the last EventLog
|
||||
List<EventEntry> lastEventEntries = lastEventLog.eventEntries;
|
||||
EventEntry lastEntry = lastEventEntries.size() > 0
|
||||
? lastEventEntries.get(lastEventEntries.size() - 1) : null;
|
||||
EventEntry secondLastEntry = lastEventEntries.size() > 1
|
||||
? lastEventEntries.get(lastEventEntries.size() - 2) : null;
|
||||
|
||||
// Update the last EventEntry if it's a duplicate
|
||||
if (isEntrySame(lastEntry, type, event, compoundString)
|
||||
&& isEntrySame(secondLastEntry, type, event, compoundString)) {
|
||||
lastEntry.update(type, event, extras, compoundString);
|
||||
secondLastEntry.duplicateCount++;
|
||||
return;
|
||||
}
|
||||
EventEntry eventEntry = new EventEntry();
|
||||
|
||||
eventEntry.update(type, event, extras, compoundString);
|
||||
lastEventEntries.add(eventEntry);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Arrays.fill(logs, null);
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter writer) {
|
||||
writer.println(prefix + "ActiveGestureLog history:");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSZ ", Locale.US);
|
||||
Date date = new Date();
|
||||
|
||||
for (int i = 0; i < logs.length; i++) {
|
||||
EventLog eventLog = logs[(nextIndex + logs.length - i - 1) % logs.length];
|
||||
if (eventLog == null) {
|
||||
continue;
|
||||
}
|
||||
writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
|
||||
|
||||
List<EventEntry> eventEntries = eventLog.eventEntries;
|
||||
for (int j = eventEntries.size() - 1; j >= 0; j--) {
|
||||
EventEntry eventEntry = eventEntries.get(j);
|
||||
date.setTime(eventEntry.time);
|
||||
|
||||
StringBuilder msg = new StringBuilder(prefix + "\t\t").append(sdf.format(date))
|
||||
.append(eventEntry.event);
|
||||
switch (eventEntry.type) {
|
||||
case TYPE_BOOL_FALSE:
|
||||
msg.append(": false");
|
||||
break;
|
||||
case TYPE_BOOL_TRUE:
|
||||
msg.append(": true");
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
msg.append(": ").append(eventEntry.extras);
|
||||
break;
|
||||
case TYPE_INTEGER:
|
||||
msg.append(": ").append((int) eventEntry.extras);
|
||||
break;
|
||||
case TYPE_INPUT_CONSUMER:
|
||||
msg.append(eventEntry.mCompoundString);
|
||||
break;
|
||||
default: // fall out
|
||||
}
|
||||
if (eventEntry.duplicateCount > 0) {
|
||||
msg.append(" & ").append(eventEntry.duplicateCount).append(" similar events");
|
||||
}
|
||||
writer.println(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments and returns the current log ID. This should be used every time a new log trace
|
||||
* is started.
|
||||
*/
|
||||
public int incrementLogId() {
|
||||
return mCurrentLogId++;
|
||||
}
|
||||
|
||||
private boolean isEntrySame(
|
||||
EventEntry entry, int type, String event, CompoundString compoundString) {
|
||||
return entry != null
|
||||
&& entry.type == type
|
||||
&& entry.event.equals(event)
|
||||
&& entry.mCompoundString.equals(compoundString);
|
||||
}
|
||||
|
||||
/** A single event entry. */
|
||||
private static class EventEntry {
|
||||
|
||||
private int type;
|
||||
private String event;
|
||||
private float extras;
|
||||
@NonNull private CompoundString mCompoundString;
|
||||
private long time;
|
||||
private int duplicateCount;
|
||||
|
||||
public void update(
|
||||
int type,
|
||||
String event,
|
||||
float extras,
|
||||
@NonNull CompoundString compoundString) {
|
||||
this.type = type;
|
||||
this.event = event;
|
||||
this.extras = extras;
|
||||
this.mCompoundString = compoundString;
|
||||
time = System.currentTimeMillis();
|
||||
duplicateCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** An entire log of entries associated with a single log ID */
|
||||
private static class EventLog {
|
||||
|
||||
private final List<EventEntry> eventEntries = new ArrayList<>();
|
||||
private final int logId;
|
||||
|
||||
protected EventLog(int logId) {
|
||||
this.logId = logId;
|
||||
}
|
||||
}
|
||||
|
||||
/** A buildable string stored as an array for memory efficiency. */
|
||||
public static class CompoundString {
|
||||
|
||||
public static final CompoundString NO_OP = new CompoundString();
|
||||
|
||||
private final List<String> mSubstrings;
|
||||
|
||||
private final boolean mIsNoOp;
|
||||
|
||||
private CompoundString() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public CompoundString(String substring) {
|
||||
mIsNoOp = substring == null;
|
||||
if (mIsNoOp) {
|
||||
mSubstrings = null;
|
||||
return;
|
||||
}
|
||||
mSubstrings = new ArrayList<>();
|
||||
mSubstrings.add(substring);
|
||||
}
|
||||
|
||||
public CompoundString append(CompoundString substring) {
|
||||
if (mIsNoOp) {
|
||||
return this;
|
||||
}
|
||||
mSubstrings.addAll(substring.mSubstrings);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompoundString append(String substring) {
|
||||
if (mIsNoOp) {
|
||||
return this;
|
||||
}
|
||||
mSubstrings.add(substring);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (mIsNoOp) {
|
||||
return "ERROR: cannot use No-Op compound string";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String substring : mSubstrings) {
|
||||
sb.append(substring);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mIsNoOp, mSubstrings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof CompoundString)) {
|
||||
return false;
|
||||
}
|
||||
CompoundString other = (CompoundString) obj;
|
||||
return mIsNoOp && other.mIsNoOp && Objects.equals(mSubstrings, other.mSubstrings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.ChecksSdkIntAtLeast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
@@ -925,4 +926,12 @@ public final class Utilities {
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
public static boolean bothNull(@Nullable Object a, @Nullable Object b) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
|
||||
public static boolean bothNonNull(@Nullable Object a, @Nullable Object b) {
|
||||
return a != null && b != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,11 @@ public final class FeatureFlags {
|
||||
* Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
|
||||
* and set a default value for the flag. This will be the default value on Debug builds.
|
||||
*/
|
||||
public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag(
|
||||
"ENABLE_INPUT_CONSUMER_REASON_LOGGING",
|
||||
false,
|
||||
"Log the reason why an Input Consumer was selected for a gesture.");
|
||||
|
||||
// When enabled the promise icon is visible in all apps while installation an app.
|
||||
public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(
|
||||
"PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.launcher3.logging;
|
||||
|
||||
|
||||
import android.util.Log;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A utility class to record and log events. Events are stored in a fixed size array and old logs
|
||||
* are purged as new events come.
|
||||
*/
|
||||
public class EventLogArray {
|
||||
|
||||
private static final int TYPE_ONE_OFF = 0;
|
||||
private static final int TYPE_FLOAT = 1;
|
||||
private static final int TYPE_INTEGER = 2;
|
||||
private static final int TYPE_BOOL_TRUE = 3;
|
||||
private static final int TYPE_BOOL_FALSE = 4;
|
||||
|
||||
private final String name;
|
||||
private final EventEntry[] logs;
|
||||
private int nextIndex;
|
||||
private int mLogId;
|
||||
|
||||
public EventLogArray(String name, int size) {
|
||||
this.name = name;
|
||||
logs = new EventEntry[size];
|
||||
nextIndex = 0;
|
||||
}
|
||||
|
||||
public void addLog(String event) {
|
||||
addLog(TYPE_ONE_OFF, event, 0);
|
||||
}
|
||||
|
||||
public void addLog(String event, int extras) {
|
||||
addLog(TYPE_INTEGER, event, extras);
|
||||
}
|
||||
|
||||
public void addLog(String event, boolean extras) {
|
||||
addLog(extras ? TYPE_BOOL_TRUE : TYPE_BOOL_FALSE, event, 0);
|
||||
}
|
||||
|
||||
private void addLog(int type, String event, float extras) {
|
||||
// Merge the logs if its a duplicate
|
||||
int last = (nextIndex + logs.length - 1) % logs.length;
|
||||
int secondLast = (nextIndex + logs.length - 2) % logs.length;
|
||||
if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) {
|
||||
logs[last].update(type, event, extras, mLogId);
|
||||
logs[secondLast].duplicateCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (logs[nextIndex] == null) {
|
||||
logs[nextIndex] = new EventEntry();
|
||||
}
|
||||
logs[nextIndex].update(type, event, extras, mLogId);
|
||||
nextIndex = (nextIndex + 1) % logs.length;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Arrays.setAll(logs, (i) -> null);
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter writer) {
|
||||
writer.println(prefix + "EventLog (" + name + ") history:");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(" HH:mm:ss.SSSZ ", Locale.US);
|
||||
Date date = new Date();
|
||||
|
||||
for (int i = 0; i < logs.length; i++) {
|
||||
EventEntry log = logs[(nextIndex + logs.length - i - 1) % logs.length];
|
||||
if (log == null) {
|
||||
continue;
|
||||
}
|
||||
date.setTime(log.time);
|
||||
|
||||
StringBuilder msg = new StringBuilder(prefix).append(sdf.format(date))
|
||||
.append(log.event);
|
||||
switch (log.type) {
|
||||
case TYPE_BOOL_FALSE:
|
||||
msg.append(": false");
|
||||
break;
|
||||
case TYPE_BOOL_TRUE:
|
||||
msg.append(": true");
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
msg.append(": ").append(log.extras);
|
||||
break;
|
||||
case TYPE_INTEGER:
|
||||
msg.append(": ").append((int) log.extras);
|
||||
break;
|
||||
default: // fall out
|
||||
}
|
||||
if (log.duplicateCount > 0) {
|
||||
msg.append(" & ").append(log.duplicateCount).append(" similar events");
|
||||
}
|
||||
msg.append(" traceId: ").append(log.traceId);
|
||||
writer.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a 3 digit random number between 100-999 */
|
||||
public int generateAndSetLogId() {
|
||||
Random r = new Random();
|
||||
mLogId = r.nextInt(900) + 100;
|
||||
return mLogId;
|
||||
}
|
||||
|
||||
private boolean isEntrySame(EventEntry entry, int type, String event) {
|
||||
return entry != null && entry.type == type && entry.event.equals(event);
|
||||
}
|
||||
|
||||
/** A single event entry. */
|
||||
private static class EventEntry {
|
||||
|
||||
private int type;
|
||||
private String event;
|
||||
private float extras;
|
||||
private long time;
|
||||
private int duplicateCount;
|
||||
private int traceId;
|
||||
|
||||
public void update(int type, String event, float extras, int traceId) {
|
||||
this.type = type;
|
||||
this.event = event;
|
||||
this.extras = extras;
|
||||
this.traceId = traceId;
|
||||
time = System.currentTimeMillis();
|
||||
duplicateCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user