Merge "New jank flag for showing CUJ names on screen" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d57e2fd6df
@@ -36,6 +36,7 @@ import android.graphics.HardwareRendererObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.Trace;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Choreographer;
|
||||
@@ -43,7 +44,9 @@ import android.view.FrameMetrics;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.JankData.JankType;
|
||||
import android.view.ThreadedRenderer;
|
||||
import android.view.View;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.WindowCallbacks;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.InteractionJankMonitor.Configuration;
|
||||
@@ -686,6 +689,14 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
}
|
||||
}
|
||||
|
||||
ThreadedRendererWrapper getThreadedRenderer() {
|
||||
return mRendererWrapper;
|
||||
}
|
||||
|
||||
ViewRootWrapper getViewRoot() {
|
||||
return mViewRoot;
|
||||
}
|
||||
|
||||
private boolean shouldTriggerPerfetto(int missedFramesCount, int maxFrameTimeNanos) {
|
||||
boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
|
||||
&& missedFramesCount >= mTraceThresholdMissedFrames;
|
||||
@@ -798,6 +809,28 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
public SurfaceControl getSurfaceControl() {
|
||||
return mViewRoot.getSurfaceControl();
|
||||
}
|
||||
|
||||
void requestInvalidateRootRenderNode() {
|
||||
mViewRoot.requestInvalidateRootRenderNode();
|
||||
}
|
||||
|
||||
void addWindowCallbacks(WindowCallbacks windowCallbacks) {
|
||||
mViewRoot.addWindowCallbacks(windowCallbacks);
|
||||
}
|
||||
|
||||
void removeWindowCallbacks(WindowCallbacks windowCallbacks) {
|
||||
mViewRoot.removeWindowCallbacks(windowCallbacks);
|
||||
}
|
||||
|
||||
View getView() {
|
||||
return mViewRoot.getView();
|
||||
}
|
||||
|
||||
int dipToPx(int dip) {
|
||||
final DisplayMetrics displayMetrics =
|
||||
mViewRoot.mContext.getResources().getDisplayMetrics();
|
||||
return (int) (displayMetrics.density * dip + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SurfaceControlWrapper {
|
||||
|
||||
@@ -97,6 +97,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
@@ -104,6 +105,7 @@ import android.annotation.UiThread;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
@@ -143,6 +145,14 @@ import java.util.concurrent.TimeUnit;
|
||||
* adb shell device_config put interaction_jank_monitor enabled true
|
||||
* adb shell device_config put interaction_jank_monitor sampling_interval 1
|
||||
*
|
||||
* On debuggable builds, an overlay can be used to display the name of the
|
||||
* currently running cuj using:
|
||||
*
|
||||
* adb shell device_config put interaction_jank_monitor debug_overlay_enabled true
|
||||
*
|
||||
* NOTE: The overlay will interfere with metrics, so it should only be used
|
||||
* for understanding which UI events correspeond to which CUJs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InteractionJankMonitor {
|
||||
@@ -159,6 +169,7 @@ public class InteractionJankMonitor {
|
||||
"trace_threshold_missed_frames";
|
||||
private static final String SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY =
|
||||
"trace_threshold_frame_time_millis";
|
||||
private static final String SETTINGS_DEBUG_OVERLAY_ENABLED_KEY = "debug_overlay_enabled";
|
||||
/** Default to being enabled on debug builds. */
|
||||
private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE;
|
||||
/** Default to collecting data for all CUJs. */
|
||||
@@ -166,6 +177,7 @@ public class InteractionJankMonitor {
|
||||
/** Default to triggering trace if 3 frames are missed OR a frame takes at least 64ms */
|
||||
private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3;
|
||||
private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
|
||||
private static final boolean DEFAULT_DEBUG_OVERLAY_ENABLED = false;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int MAX_LENGTH_OF_CUJ_NAME = 80;
|
||||
@@ -343,6 +355,9 @@ public class InteractionJankMonitor {
|
||||
private final HandlerThread mWorker;
|
||||
private final DisplayResolutionTracker mDisplayResolutionTracker;
|
||||
private final Object mLock = new Object();
|
||||
private @ColorInt int mDebugBgColor = Color.CYAN;
|
||||
private double mDebugYOffset = 0.1;
|
||||
private InteractionMonitorDebugOverlay mDebugOverlay;
|
||||
|
||||
private volatile boolean mEnabled = DEFAULT_ENABLED;
|
||||
private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
|
||||
@@ -533,7 +548,7 @@ public class InteractionJankMonitor {
|
||||
if (needRemoveTasks(action, session)) {
|
||||
getTracker(session.getCuj()).getHandler().runWithScissors(() -> {
|
||||
removeTimeout(session.getCuj());
|
||||
removeTracker(session.getCuj());
|
||||
removeTracker(session.getCuj(), session.getReason());
|
||||
}, EXECUTOR_TASK_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@@ -699,7 +714,7 @@ public class InteractionJankMonitor {
|
||||
if (tracker == null) return false;
|
||||
// if the end call doesn't return true, another thread is handling end of the cuj.
|
||||
if (tracker.end(REASON_END_NORMAL)) {
|
||||
removeTracker(cujType);
|
||||
removeTracker(cujType, REASON_END_NORMAL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -750,7 +765,7 @@ public class InteractionJankMonitor {
|
||||
if (tracker == null) return false;
|
||||
// if the cancel call doesn't return true, another thread is handling cancel of the cuj.
|
||||
if (tracker.cancel(reason)) {
|
||||
removeTracker(cujType);
|
||||
removeTracker(cujType, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -758,6 +773,13 @@ public class InteractionJankMonitor {
|
||||
private void putTracker(@CujType int cuj, @NonNull FrameTracker tracker) {
|
||||
synchronized (mLock) {
|
||||
mRunningTrackers.put(cuj, tracker);
|
||||
if (mDebugOverlay != null) {
|
||||
mDebugOverlay.onTrackerAdded(cuj, tracker.getViewRoot());
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Added tracker for " + getNameOfCuj(cuj)
|
||||
+ ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,9 +789,16 @@ public class InteractionJankMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTracker(@CujType int cuj) {
|
||||
private void removeTracker(@CujType int cuj, int reason) {
|
||||
synchronized (mLock) {
|
||||
mRunningTrackers.remove(cuj);
|
||||
if (mDebugOverlay != null) {
|
||||
mDebugOverlay.onTrackerRemoved(cuj, reason, mRunningTrackers);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Removed tracker for " + getNameOfCuj(cuj)
|
||||
+ ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,6 +811,16 @@ public class InteractionJankMonitor {
|
||||
mTraceThresholdFrameTimeMillis = properties.getInt(
|
||||
SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY,
|
||||
DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
|
||||
// Never allow the debug overlay to be used on user builds
|
||||
boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean(
|
||||
SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
|
||||
DEFAULT_DEBUG_OVERLAY_ENABLED);
|
||||
if (debugOverlayEnabled && mDebugOverlay == null) {
|
||||
mDebugOverlay = new InteractionMonitorDebugOverlay(mDebugBgColor, mDebugYOffset);
|
||||
} else if (!debugOverlayEnabled && mDebugOverlay != null) {
|
||||
mDebugOverlay.dispose();
|
||||
mDebugOverlay = null;
|
||||
}
|
||||
// The memory visibility is powered by the volatile field, mEnabled.
|
||||
mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
|
||||
}
|
||||
@@ -821,6 +860,39 @@ public class InteractionJankMonitor {
|
||||
return interactionType - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the debug overlay used for displaying interaction names on the screen while they
|
||||
* occur.
|
||||
*
|
||||
* @param bgColor the background color of the box used to display the CUJ names
|
||||
* @param yOffset number between 0 and 1 to indicate where the top of the box should be relative
|
||||
* to the height of the screen
|
||||
*/
|
||||
public void configDebugOverlay(@ColorInt int bgColor, double yOffset) {
|
||||
mDebugBgColor = bgColor;
|
||||
mDebugYOffset = yOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for getting a string representation of all running CUJs. For example,
|
||||
* "(LOCKSCREEN_TRANSITION_FROM_AOD, IME_INSETS_ANIMATION)"
|
||||
*/
|
||||
private static String listNamesOfCujs(SparseArray<FrameTracker> trackers) {
|
||||
if (!DEBUG) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
sb.append(getNameOfCuj(trackers.keyAt(i)));
|
||||
if (i < trackers.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to translate CUJ type to CUJ name.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.internal.jank;
|
||||
|
||||
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RecordingCanvas;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Trace;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.WindowCallbacks;
|
||||
|
||||
import com.android.internal.jank.FrameTracker.Reasons;
|
||||
import com.android.internal.jank.InteractionJankMonitor.CujType;
|
||||
|
||||
/**
|
||||
* An overlay that uses WindowCallbacks to draw the names of all running CUJs to the window
|
||||
* associated with one of the CUJs being tracked. There's no guarantee which window it will
|
||||
* draw to. NOTE: sometimes the CUJ names will remain displayed on the screen longer than they
|
||||
* are actually running.
|
||||
* <p>
|
||||
* CUJ names will be drawn as follows:
|
||||
* <ul>
|
||||
* <li> Normal text indicates the CUJ is currently running
|
||||
* <li> Grey text indicates the CUJ ended normally and is no longer running
|
||||
* <li> Red text with a strikethrough indicates the CUJ was canceled or ended abnormally
|
||||
* </ul>
|
||||
*/
|
||||
class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
||||
private static final int REASON_STILL_RUNNING = -1000;
|
||||
// Sparse array where the key in the CUJ and the value is the session status, or null if
|
||||
// it's currently running
|
||||
private final SparseIntArray mRunningCujs = new SparseIntArray();
|
||||
private FrameTracker.ViewRootWrapper mViewRoot = null;
|
||||
private final Paint mDebugPaint;
|
||||
private final Paint.FontMetrics mDebugFontMetrics;
|
||||
// Used to display the overlay in a different color and position for different processes.
|
||||
// Otherwise, two overlays will overlap and be difficult to read.
|
||||
private final int mBgColor;
|
||||
private final double mYOffset;
|
||||
private final String mPackageName;
|
||||
|
||||
InteractionMonitorDebugOverlay(@ColorInt int bgColor, double yOffset) {
|
||||
mBgColor = bgColor;
|
||||
mYOffset = yOffset;
|
||||
mDebugPaint = new Paint();
|
||||
mDebugPaint.setAntiAlias(false);
|
||||
mDebugFontMetrics = new Paint.FontMetrics();
|
||||
final Context context = ActivityThread.currentApplication();
|
||||
mPackageName = context.getPackageName();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (mViewRoot != null) {
|
||||
mViewRoot.removeWindowCallbacks(this);
|
||||
forceRedraw();
|
||||
}
|
||||
mViewRoot = null;
|
||||
}
|
||||
|
||||
private boolean attachViewRootIfNeeded(FrameTracker.ViewRootWrapper viewRoot) {
|
||||
if (mViewRoot == null && viewRoot != null) {
|
||||
mViewRoot = viewRoot;
|
||||
viewRoot.addWindowCallbacks(this);
|
||||
forceRedraw();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private float getWidthOfLongestCujName(int cujFontSize) {
|
||||
mDebugPaint.setTextSize(cujFontSize);
|
||||
float maxLength = 0;
|
||||
for (int i = 0; i < mRunningCujs.size(); i++) {
|
||||
String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
|
||||
float textLength = mDebugPaint.measureText(cujName);
|
||||
if (textLength > maxLength) {
|
||||
maxLength = textLength;
|
||||
}
|
||||
}
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
private float getTextHeight(int textSize) {
|
||||
mDebugPaint.setTextSize(textSize);
|
||||
mDebugPaint.getFontMetrics(mDebugFontMetrics);
|
||||
return mDebugFontMetrics.descent - mDebugFontMetrics.ascent;
|
||||
}
|
||||
|
||||
private int dipToPx(int dip) {
|
||||
if (mViewRoot != null) {
|
||||
return mViewRoot.dipToPx(dip);
|
||||
} else {
|
||||
return dip;
|
||||
}
|
||||
}
|
||||
|
||||
private void forceRedraw() {
|
||||
if (mViewRoot != null) {
|
||||
mViewRoot.requestInvalidateRootRenderNode();
|
||||
mViewRoot.getView().invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void onTrackerRemoved(@CujType int removedCuj, @Reasons int reason,
|
||||
SparseArray<FrameTracker> runningTrackers) {
|
||||
mRunningCujs.put(removedCuj, reason);
|
||||
// If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
|
||||
if (mRunningCujs.indexOfValue(REASON_STILL_RUNNING) < 0) {
|
||||
mRunningCujs.clear();
|
||||
dispose();
|
||||
} else {
|
||||
boolean needsNewViewRoot = true;
|
||||
if (mViewRoot != null) {
|
||||
// Check to see if this viewroot is still associated with one of the running
|
||||
// trackers
|
||||
for (int i = 0; i < runningTrackers.size(); i++) {
|
||||
if (mViewRoot.equals(
|
||||
runningTrackers.valueAt(i).getViewRoot())) {
|
||||
needsNewViewRoot = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needsNewViewRoot) {
|
||||
dispose();
|
||||
for (int i = 0; i < runningTrackers.size(); i++) {
|
||||
if (attachViewRootIfNeeded(runningTrackers.valueAt(i).getViewRoot())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
forceRedraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onTrackerAdded(@CujType int addedCuj, FrameTracker.ViewRootWrapper viewRoot) {
|
||||
// Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
|
||||
// is still running
|
||||
mRunningCujs.put(addedCuj, REASON_STILL_RUNNING);
|
||||
attachViewRootIfNeeded(viewRoot);
|
||||
forceRedraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen,
|
||||
Rect systemInsets, Rect stableInsets) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen,
|
||||
Rect systemInsets, Rect stableInsets) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowDragResizeEnd() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDraw(boolean reportNextDraw) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostDraw(RecordingCanvas canvas) {
|
||||
Trace.beginSection("InteractionJankMonitor#drawDebug");
|
||||
final int padding = dipToPx(5);
|
||||
final int h = canvas.getHeight();
|
||||
final int w = canvas.getWidth();
|
||||
// Draw sysui CUjs near the bottom of the screen so they don't overlap with the shade,
|
||||
// and draw launcher CUJs near the top of the screen so they don't overlap with gestures
|
||||
final int dy = (int) (h * mYOffset);
|
||||
int packageNameFontSize = dipToPx(12);
|
||||
int cujFontSize = dipToPx(18);
|
||||
final float cujNameTextHeight = getTextHeight(cujFontSize);
|
||||
final float packageNameTextHeight = getTextHeight(packageNameFontSize);
|
||||
float maxLength = getWidthOfLongestCujName(cujFontSize);
|
||||
|
||||
final int dx = (int) ((w - maxLength) / 2f);
|
||||
canvas.translate(dx, dy);
|
||||
// Draw background rectangle for displaying the text showing the CUJ name
|
||||
mDebugPaint.setColor(mBgColor);
|
||||
canvas.drawRect(
|
||||
-padding * 2, // more padding on top so we can draw the package name
|
||||
-padding,
|
||||
padding * 2 + maxLength,
|
||||
padding * 2 + packageNameTextHeight + cujNameTextHeight * mRunningCujs.size(),
|
||||
mDebugPaint);
|
||||
mDebugPaint.setTextSize(packageNameFontSize);
|
||||
mDebugPaint.setColor(Color.BLACK);
|
||||
mDebugPaint.setStrikeThruText(false);
|
||||
canvas.translate(0, packageNameTextHeight);
|
||||
canvas.drawText("package:" + mPackageName, 0, 0, mDebugPaint);
|
||||
mDebugPaint.setTextSize(cujFontSize);
|
||||
// Draw text for CUJ names
|
||||
for (int i = 0; i < mRunningCujs.size(); i++) {
|
||||
int status = mRunningCujs.valueAt(i);
|
||||
if (status == REASON_STILL_RUNNING) {
|
||||
mDebugPaint.setColor(Color.BLACK);
|
||||
mDebugPaint.setStrikeThruText(false);
|
||||
} else if (status == REASON_END_NORMAL) {
|
||||
mDebugPaint.setColor(Color.GRAY);
|
||||
mDebugPaint.setStrikeThruText(false);
|
||||
} else {
|
||||
// Cancelled, or otherwise ended for a bad reason
|
||||
mDebugPaint.setColor(Color.RED);
|
||||
mDebugPaint.setStrikeThruText(true);
|
||||
}
|
||||
String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
|
||||
canvas.translate(0, cujNameTextHeight);
|
||||
canvas.drawText(cujName, 0, 0, mDebugPaint);
|
||||
}
|
||||
Trace.endSection();
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.SensorPrivacyManager;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
@@ -113,13 +114,13 @@ import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dagger.qualifiers.TestHarness;
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
/**
|
||||
* Provides Non-SystemUI, Framework-Owned instances to the dependency graph.
|
||||
*/
|
||||
@@ -323,7 +324,9 @@ public class FrameworkServicesModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
static InteractionJankMonitor provideInteractionJankMonitor() {
|
||||
return InteractionJankMonitor.getInstance();
|
||||
InteractionJankMonitor jankMonitor = InteractionJankMonitor.getInstance();
|
||||
jankMonitor.configDebugOverlay(Color.YELLOW, 0.75);
|
||||
return jankMonitor;
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
Reference in New Issue
Block a user