blob: d433d989419614633b84195fea040004ef02b581 [file] [log] [blame]
/*
* Copyright (C) 2014 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 android.support.test.jank;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.util.Log;
import android.view.FrameStats;
import android.view.accessibility.AccessibilityWindowInfo;
/** The {@link JankUtil} class provides functionality for monitoring jank. */
public class JankUtil {
private static final String TAG = JankUtil.class.getSimpleName();
// Singleton instance
private static JankUtil sInstance;
private UiAutomation mUiAutomation;
private JankMonitor mMonitor;
/** Private constructor. Clients should use {@link JankUtil#getInstance(Instrumentation)}. */
private JankUtil(UiAutomation automation) {
mUiAutomation = automation;
// Subscribe to window information
AccessibilityServiceInfo info = mUiAutomation.getServiceInfo();
info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
mUiAutomation.setServiceInfo(info);
}
/** Returns a {@link JankUtil} instance. */
public static JankUtil getInstance(Instrumentation instrumentation) {
if (sInstance == null) {
sInstance = new JankUtil(instrumentation.getUiAutomation());
}
return sInstance;
}
/** Starts monitoring for janky frames of the given {@code type}. */
public void startMonitor(JankType type) {
if (mMonitor != null) {
throw new IllegalStateException("Monitor already started");
}
if (type == JankType.CONTENT_FRAMES) {
mMonitor = new WindowContentJankMonitor();
} else if (type == JankType.ANIMATION_FRAMES) {
mMonitor = new WindowAnimationJankMonitor();
} else {
throw new RuntimeException("Invalid type");
}
mMonitor.clear();
}
/** Stops monitoring and returns the {@link JankResult} for this monitoring session. */
public JankResult stopMonitor() {
FrameStats stats = mMonitor.getStats();
mMonitor = null;
return JankResult.analyze(stats);
}
/** Returns the id of the current application window. */
private int getCurrentWindow() {
for (AccessibilityWindowInfo window : mUiAutomation.getWindows()) {
if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
return window.getId();
}
}
throw new RuntimeException("No application window found");
}
/** Generic monitoring interface */
private static interface JankMonitor {
public void clear();
public FrameStats getStats();
}
/** Monitor for detecting window content frame jank. */
private class WindowContentJankMonitor implements JankMonitor {
private int mWindowId = -1;
@Override
public void clear() {
mWindowId = getCurrentWindow();
mUiAutomation.clearWindowContentFrameStats(mWindowId);
}
@Override
public FrameStats getStats() {
int currentWindow = getCurrentWindow();
if (currentWindow != mWindowId) {
Log.w(TAG, "Current window changed during the test. Did you mean to measure " +
"ANIMATION_FRAMES?");
}
mWindowId = -1;
return mUiAutomation.getWindowContentFrameStats(currentWindow);
}
}
/** Monitor for detecting window animation frame jank. */
private class WindowAnimationJankMonitor implements JankMonitor {
@Override
public void clear() {
mUiAutomation.clearWindowAnimationFrameStats();
}
@Override
public FrameStats getStats() {
return mUiAutomation.getWindowAnimationFrameStats();
}
}
}