diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java index e02c6960a4..109a4c5f79 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java @@ -77,6 +77,11 @@ public class AssistantTouchConsumer implements InputConsumer { WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); } + @Override + public int getType() { + return TYPE_ASSISTANT; + } + @Override public void onMotionEvent(MotionEvent ev) { // TODO add logging diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java index 047f34c2d4..d919a3e711 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java @@ -30,6 +30,11 @@ public class DeviceLockedInputConsumer implements InputConsumer { mContext = context; } + @Override + public int getType() { + return TYPE_DEVICE_LOCKED; + } + @Override public void onMotionEvent(MotionEvent ev) { // For now, just start the home intent so user is prompted to unlock the device. diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java index 8dfb9abdda..ad9fe78f85 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java @@ -23,7 +23,16 @@ import android.view.MotionEvent; @TargetApi(Build.VERSION_CODES.O) public interface InputConsumer { - InputConsumer NO_OP = new InputConsumer() { }; + + int TYPE_NO_OP = 0; + int TYPE_OVERVIEW = 1; + int TYPE_OTHER_ACTIVITY = 2; + int TYPE_ASSISTANT = 3; + int TYPE_DEVICE_LOCKED = 4; + + InputConsumer NO_OP = () -> TYPE_NO_OP; + + int getType(); default boolean isActive() { return false; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java index 67bfeaa24e..e3afb92dbf 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java @@ -147,6 +147,11 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mPassedTouchSlop = mPassedDragSlop = mSwipeSharedState.getActiveListener() != null; } + @Override + public int getType() { + return TYPE_OTHER_ACTIVITY; + } + @Override public void onMotionEvent(MotionEvent ev) { if (mVelocityTracker == null) { @@ -225,7 +230,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTouchSlop) { mPassedTouchSlop = true; - TOUCH_INTERACTION_LOG.startQuickStep(); + TOUCH_INTERACTION_LOG.addLog("startQuickstep"); if (mIsDeferredDownTarget) { // Deferred gesture, start the animation and gesture tracking once // we pass the actual touch slop @@ -288,7 +293,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void startTouchTrackingForWindowAnimation(long touchTimeMs) { - TOUCH_INTERACTION_LOG.startRecentsAnimation(); + TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation"); RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener(); final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler( diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java index 28c4db46a3..cce5cb3f04 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java @@ -59,6 +59,11 @@ public class OverviewInputConsumer mStartingInActivityBounds = startingInActivityBounds; } + @Override + public int getType() { + return TYPE_OVERVIEW; + } + @Override public void onMotionEvent(MotionEvent ev) { if (mInvalidated) { @@ -120,7 +125,7 @@ public class OverviewInputConsumer OverviewCallbacks.get(mActivity).closeAllWindows(); ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - TOUCH_INTERACTION_LOG.startQuickStep(); + TOUCH_INTERACTION_LOG.addLog("startQuickstep"); } mTrackingStarted = true; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java deleted file mode 100644 index 4b660d4cf8..0000000000 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.view.MotionEvent; -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.LinkedList; - -/** - * Keeps track of debugging logs for a particular quickstep gesture. - */ -public class TouchInteractionLog { - - // The number of gestures to log - private static final int MAX_NUM_LOG_GESTURES = 5; - - private final Calendar mCalendar = Calendar.getInstance(); - private final SimpleDateFormat mDateFormat = new SimpleDateFormat("MMM dd - kk:mm:ss:SSS"); - private final LinkedList> mGestureLogs = new LinkedList<>(); - - public void prepareForNewGesture() { - mGestureLogs.add(new ArrayList<>()); - while (mGestureLogs.size() > MAX_NUM_LOG_GESTURES) { - mGestureLogs.pop(); - } - getCurrentLog().add("[" + mDateFormat.format(mCalendar.getTime()) + "]"); - } - - public void setInputConsumer(InputConsumer consumer) { - getCurrentLog().add("tc=" + consumer.getClass().getSimpleName()); - } - - public void addMotionEvent(MotionEvent event) { - getCurrentLog().add("ev=" + event.getActionMasked()); - } - - public void startQuickStep() { - getCurrentLog().add("qstStart"); - } - - public void startRecentsAnimation() { - getCurrentLog().add("raStart"); - } - - public void startRecentsAnimationCallback(int numTargets) { - getCurrentLog().add("raStartCb=" + numTargets); - } - - public void cancelRecentsAnimation() { - getCurrentLog().add("raCancel"); - } - - public void finishRecentsAnimation(boolean toHome) { - getCurrentLog().add("raFinish=" + toHome); - } - - public void dump(PrintWriter pw) { - pw.println("TouchInteractionLog {"); - for (ArrayList gesture : mGestureLogs) { - pw.print(" "); - for (String log : gesture) { - pw.print(log + " "); - } - pw.println(); - } - pw.println("}"); - } - - private ArrayList getCurrentLog() { - return mGestureLogs.getLast(); - } -} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index d1d0e864df..a3c3ff9655 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -45,6 +45,7 @@ import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.Utilities; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.logging.EventLogArray; import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.UiThreadHelper; import com.android.systemui.shared.recents.IOverviewProxy; @@ -70,7 +71,8 @@ public class TouchInteractionService extends Service { public static final LooperExecutor BACKGROUND_EXECUTOR = new LooperExecutor(UiThreadHelper.getBackgroundLooper()); - public static final TouchInteractionLog TOUCH_INTERACTION_LOG = new TouchInteractionLog(); + public static final EventLogArray TOUCH_INTERACTION_LOG = + new EventLogArray("touch_interaction_log", 40); public static final int EDGE_NAV_BAR = 1 << 8; @@ -281,15 +283,13 @@ public class TouchInteractionService extends Service { return; } MotionEvent event = (MotionEvent) ev; + TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked()); if (event.getAction() == ACTION_DOWN) { - TOUCH_INTERACTION_LOG.prepareForNewGesture(); boolean useSharedState = mConsumer.isActive(); mConsumer.onConsumerAboutToBeSwitched(); mConsumer = newConsumer(useSharedState, event); - TOUCH_INTERACTION_LOG.setInputConsumer(mConsumer); + TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType()); } - TOUCH_INTERACTION_LOG.addMotionEvent(event); - mConsumer.onMotionEvent(event); } @@ -342,6 +342,6 @@ public class TouchInteractionService extends Service { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - TOUCH_INTERACTION_LOG.dump(pw); + TOUCH_INTERACTION_LOG.dump("", pw); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index fa827e793f..7dc58a58c3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -671,7 +671,7 @@ public class WindowTransformSwipeHandler initTransitionEndpoints(dp); mRecentsAnimationWrapper.setController(targetSet); - TOUCH_INTERACTION_LOG.startRecentsAnimationCallback(targetSet.apps.length); + TOUCH_INTERACTION_LOG.addLog("startRecentsAnimationCallback", targetSet.apps.length); setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); mPassedOverviewThreshold = false; @@ -682,7 +682,7 @@ public class WindowTransformSwipeHandler mRecentsAnimationWrapper.setController(null); mActivityInitListener.unregister(); setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); - TOUCH_INTERACTION_LOG.cancelRecentsAnimation(); + TOUCH_INTERACTION_LOG.addLog("cancelRecentsAnimation"); } @UiThread @@ -1025,7 +1025,7 @@ public class WindowTransformSwipeHandler @UiThread private void resumeLastTask() { mRecentsAnimationWrapper.finish(false /* toRecents */, null); - TOUCH_INTERACTION_LOG.finishRecentsAnimation(false); + TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false); } @UiThread @@ -1043,7 +1043,7 @@ public class WindowTransformSwipeHandler mMainThreadHandler); }); } - TOUCH_INTERACTION_LOG.finishRecentsAnimation(false); + TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false); doLogGesture(NEW_TASK); } @@ -1152,7 +1152,7 @@ public class WindowTransformSwipeHandler () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } } - TOUCH_INTERACTION_LOG.finishRecentsAnimation(true); + TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true); } private void finishCurrentTransitionToHome() { @@ -1160,7 +1160,7 @@ public class WindowTransformSwipeHandler mRecentsAnimationWrapper.finish(true /* toRecents */, () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } - TOUCH_INTERACTION_LOG.finishRecentsAnimation(true); + TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true); doLogGesture(HOME); } diff --git a/src/com/android/launcher3/logging/EventLogArray.java b/src/com/android/launcher3/logging/EventLogArray.java new file mode 100644 index 0000000000..bfb3792273 --- /dev/null +++ b/src/com/android/launcher3/logging/EventLogArray.java @@ -0,0 +1,136 @@ +/* + * 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 java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * 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; + + 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, float extras) { + addLog(TYPE_FLOAT, 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); + logs[secondLast].duplicateCount++; + return; + } + + if (logs[nextIndex] == null) { + logs[nextIndex] = new EventEntry(); + } + logs[nextIndex].update(type, event, extras); + nextIndex = (nextIndex + 1) % logs.length; + } + + public void dump(String prefix, PrintWriter writer) { + writer.println(prefix + name + " event 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"); + } + writer.println(msg); + } + } + + 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; + + public void update(int type, String event, float extras) { + this.type = type; + this.event = event; + this.extras = extras; + time = System.currentTimeMillis(); + duplicateCount = 0; + } + } +}