Adding render stats APIs to UiAutomation (framework).

bug:12927198

Change-Id: Iae21481c75ae58dcdab3731bf5f1e2844e29d434
This commit is contained in:
Svetoslav
2014-03-13 11:17:26 -07:00
parent ed3db02c05
commit 1376d600d8
21 changed files with 1004 additions and 18 deletions

View File

@@ -19,6 +19,8 @@ package android.app;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.graphics.Bitmap;
import android.view.InputEvent;
import android.view.WindowContentFrameStats;
import android.view.WindowAnimationFrameStats;
import android.os.ParcelFileDescriptor;
/**
@@ -26,7 +28,7 @@ import android.os.ParcelFileDescriptor;
* on behalf of an instrumentation that it runs. These operations require
* special permissions which the shell user has but the instrumentation does
* not. Running privileged operations by the shell user on behalf of an
* instrumentation is needed for running UiTestCases.
* instrumentation is needed for running UiTestCases.
*
* {@hide}
*/
@@ -37,4 +39,8 @@ interface IUiAutomationConnection {
boolean setRotation(int rotation);
Bitmap takeScreenshot(int width, int height);
void shutdown();
boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
WindowAnimationFrameStats getWindowAnimationFrameStats();
}

View File

@@ -33,6 +33,8 @@ import android.view.Display;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.WindowAnimationFrameStats;
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -674,6 +676,148 @@ public final class UiAutomation {
}
}
/**
* Clears the frame statistics for the content of a given window. These
* statistics contain information about the most recently rendered content
* frames.
*
* @param windowId The window id.
* @return Whether the window is present and its frame statistics
* were cleared.
*
* @see android.view.WindowContentFrameStats
* @see #getWindowContentFrameStats(int)
* @see #getWindows()
* @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
*/
public boolean clearWindowContentFrameStats(int windowId) {
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId);
}
// Calling out without a lock held.
return mUiAutomationConnection.clearWindowContentFrameStats(windowId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error clearing window content frame stats!", re);
}
return false;
}
/**
* Gets the frame statistics for a given window. These statistics contain
* information about the most recently rendered content frames.
* <p>
* A typical usage requires clearing the window frame statistics via {@link
* #clearWindowContentFrameStats(int)} followed by an interaction with the UI and
* finally getting the window frame statistics via calling this method.
* </p>
* <pre>
* // Assume we have at least one window.
* final int windowId = getWindows().get(0).getId();
*
* // Start with a clean slate.
* uiAutimation.clearWindowContentFrameStats(windowId);
*
* // Do stuff with the UI.
*
* // Get the frame statistics.
* WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
* </pre>
*
* @param windowId The window id.
* @return The window frame statistics, or null if the window is not present.
*
* @see android.view.WindowContentFrameStats
* @see #clearWindowContentFrameStats(int)
* @see #getWindows()
* @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
*/
public WindowContentFrameStats getWindowContentFrameStats(int windowId) {
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId);
}
// Calling out without a lock held.
return mUiAutomationConnection.getWindowContentFrameStats(windowId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error getting window content frame stats!", re);
}
return null;
}
/**
* Clears the window animation rendering statistics. These statistics contain
* information about the most recently rendered window animation frames, i.e.
* for window transition animations.
*
* @see android.view.WindowAnimationFrameStats
* @see #getWindowAnimationFrameStats()
* @see android.R.styleable#WindowAnimation
*/
public void clearWindowAnimationFrameStats() {
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Clearing window animation frame stats");
}
// Calling out without a lock held.
mUiAutomationConnection.clearWindowAnimationFrameStats();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error clearing window animation frame stats!", re);
}
}
/**
* Gets the window animation frame statistics. These statistics contain
* information about the most recently rendered window animation frames, i.e.
* for window transition animations.
*
* <p>
* A typical usage requires clearing the window animation frame statistics via
* {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes
* a window transition which uses a window animation and finally getting the window
* animation frame statistics by calling this method.
* </p>
* <pre>
* // Start with a clean slate.
* uiAutimation.clearWindowAnimationFrameStats();
*
* // Do stuff to trigger a window transition.
*
* // Get the frame statistics.
* WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
* </pre>
*
* @return The window animation frame statistics.
*
* @see android.view.WindowAnimationFrameStats
* @see #clearWindowAnimationFrameStats()
* @see android.R.styleable#WindowAnimation
*/
public WindowAnimationFrameStats getWindowAnimationFrameStats() {
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Getting window animation frame stats");
}
// Calling out without a lock held.
return mUiAutomationConnection.getWindowAnimationFrameStats();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error getting window animation frame stats!", re);
}
return null;
}
private static float getDegreesForRotation(int value) {
switch (value) {
case Surface.ROTATION_90: {

View File

@@ -22,12 +22,15 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.view.IWindowManager;
import android.view.InputEvent;
import android.view.SurfaceControl;
import android.view.WindowAnimationFrameStats;
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
@@ -47,6 +50,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Service.WINDOW_SERVICE));
private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
private final Object mLock = new Object();
private final Binder mToken = new Binder();
@@ -143,6 +149,76 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
}
@Override
public boolean clearWindowContentFrameStats(int windowId) throws RemoteException {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
IBinder token = mAccessibilityManager.getWindowToken(windowId);
if (token == null) {
return false;
}
return mWindowManager.clearWindowContentFrameStats(token);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public WindowContentFrameStats getWindowContentFrameStats(int windowId) throws RemoteException {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
IBinder token = mAccessibilityManager.getWindowToken(windowId);
if (token == null) {
return null;
}
return mWindowManager.getWindowContentFrameStats(token);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void clearWindowAnimationFrameStats() {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
SurfaceControl.clearAnimationFrameStats();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public WindowAnimationFrameStats getWindowAnimationFrameStats() {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
WindowAnimationFrameStats stats = new WindowAnimationFrameStats();
SurfaceControl.getAnimationFrameStats(stats);
return stats;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void shutdown() {
synchronized (mLock) {

View File

@@ -0,0 +1,19 @@
/**
* 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.view;
parcelable AnimationRenderStats;

View File

@@ -0,0 +1,97 @@
/*
* 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.view;
import android.os.Parcel;
import android.os.Parcelable;
/**
* This is the base class for frame statistics.
*/
public abstract class FrameStats {
/**
* Undefined time.
*/
public static final long UNDEFINED_TIME_NANO = -1;
protected long mRefreshPeriodNano;
protected long[] mFramesPresentedTimeNano;
/**
* Gets the refresh period of the display hosting the window(s) for
* which these statistics apply.
*
* @return The refresh period in nanoseconds.
*/
public final long getRefreshPeriodNano() {
return mRefreshPeriodNano;
}
/**
* Gets the number of frames for which there is data.
*
* @return The number of frames.
*/
public final int getFrameCount() {
return mFramesPresentedTimeNano != null
? mFramesPresentedTimeNano.length : 0;
}
/**
* Gets the start time of the interval for which these statistics
* apply. The start interval is the time when the first frame was
* presented.
*
* @return The start time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
* if there is no frame data.
*/
public final long getStartTimeNano() {
if (getFrameCount() <= 0) {
return UNDEFINED_TIME_NANO;
}
return mFramesPresentedTimeNano[0];
}
/**
* Gets the end time of the interval for which these statistics
* apply. The end interval is the time when the last frame was
* presented.
*
* @return The end time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
* if there is no frame data.
*/
public final long getEndTimeNano() {
if (getFrameCount() <= 0) {
return UNDEFINED_TIME_NANO;
}
return mFramesPresentedTimeNano[mFramesPresentedTimeNano.length - 1];
}
/**
* Get the time a frame at a given index was presented.
*
* @param index The frame index.
* @return The presented time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
* if the frame is not presented yet.
*/
public final long getFramePresentedTimeNano(int index) {
if (mFramesPresentedTimeNano == null) {
throw new IndexOutOfBoundsException();
}
return mFramesPresentedTimeNano[index];
}
}

View File

@@ -37,6 +37,7 @@ import android.view.MotionEvent;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.IInputFilter;
import android.view.WindowContentFrameStats;
/**
* System private interface to the window manager.
@@ -233,4 +234,20 @@ interface IWindowManager
* Device is in safe mode.
*/
boolean isSafeModeEnabled();
/**
* Clears the frame statistics for a given window.
*
* @param token The window token.
* @return Whether the frame statistics were cleared.
*/
boolean clearWindowContentFrameStats(IBinder token);
/**
* Gets the content frame statistics for a given window.
*
* @param token The window token.
* @return The frame statistics or null if the window does not exist.
*/
WindowContentFrameStats getWindowContentFrameStats(IBinder token);
}

View File

@@ -20,7 +20,6 @@ import dalvik.system.CloseGuard;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.Surface;
import android.os.IBinder;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
@@ -59,6 +58,11 @@ public class SurfaceControl {
private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
private static native void nativeSetLayerStack(long nativeObject, int layerStack);
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
private static native boolean nativeClearAnimationFrameStats();
private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
private static native IBinder nativeCreateDisplay(String name, boolean secure);
private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -357,6 +361,24 @@ public class SurfaceControl {
nativeSetTransparentRegionHint(mNativeObject, region);
}
public boolean clearContentFrameStats() {
checkNotReleased();
return nativeClearContentFrameStats(mNativeObject);
}
public boolean getContentFrameStats(WindowContentFrameStats outStats) {
checkNotReleased();
return nativeGetContentFrameStats(mNativeObject, outStats);
}
public static boolean clearAnimationFrameStats() {
return nativeClearAnimationFrameStats();
}
public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
return nativeGetAnimationFrameStats(outStats);
}
/**
* Sets an alpha value for the entire Surface. This value is combined with the
* per-pixel alpha. It may be used with opaque Surfaces.
@@ -542,7 +564,6 @@ public class SurfaceControl {
return nativeGetBuiltInDisplay(builtInDisplayId);
}
/**
* Copy the current screen contents into the provided {@link Surface}
*
@@ -592,7 +613,6 @@ public class SurfaceControl {
screenshot(display, consumer, 0, 0, 0, 0, true, false);
}
/**
* Copy the current screen contents into a bitmap and return it.
*
@@ -626,8 +646,8 @@ public class SurfaceControl {
}
/**
* Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
* Surfaces in the screenshot.
* Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
* includes all Surfaces in the screenshot.
*
* @param width The desired width of the returned bitmap; the raw
* screen will be scaled down to this size.

View File

@@ -0,0 +1,19 @@
/**
* 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.view;
parcelable WindowAnimationFrameStats;

View File

@@ -0,0 +1,94 @@
/*
* 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.view;
import android.os.Parcel;
import android.os.Parcelable;
/**
* This class contains window animation frame statistics. For example, a window
* animation is usually performed when the application is transitioning from one
* activity to another. The frame statistics are a snapshot for the time interval
* from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
* <p>
* The key idea is that in order to provide a smooth user experience the system should
* run window animations at a specific time interval obtained by calling {@link
* #getRefreshPeriodNano()}. If the system does not render a frame every refresh
* period the user will see irregular window transitions. The time when the frame was
* actually presented on the display by calling {@link #getFramePresentedTimeNano(int)}.
*/
public final class WindowAnimationFrameStats extends FrameStats implements Parcelable {
/**
* @hide
*/
public WindowAnimationFrameStats() {
/* do nothing */
}
/**
* Initializes this isntance.
*
* @param refreshPeriodNano The display refresh period.
* @param framesPresentedTimeNano The presented frame times.
*
* @hide
*/
public void init(long refreshPeriodNano, long[] framesPresentedTimeNano) {
mRefreshPeriodNano = refreshPeriodNano;
mFramesPresentedTimeNano = framesPresentedTimeNano;
}
private WindowAnimationFrameStats(Parcel parcel) {
mRefreshPeriodNano = parcel.readLong();
mFramesPresentedTimeNano = parcel.createLongArray();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(mRefreshPeriodNano);
parcel.writeLongArray(mFramesPresentedTimeNano);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WindowAnimationFrameStats[");
builder.append("frameCount:" + getFrameCount());
builder.append(", fromTimeNano:" + getStartTimeNano());
builder.append(", toTimeNano:" + getEndTimeNano());
builder.append(']');
return builder.toString();
}
public static final Creator<WindowAnimationFrameStats> CREATOR =
new Creator<WindowAnimationFrameStats>() {
@Override
public WindowAnimationFrameStats createFromParcel(Parcel parcel) {
return new WindowAnimationFrameStats(parcel);
}
@Override
public WindowAnimationFrameStats[] newArray(int size) {
return new WindowAnimationFrameStats[size];
}
};
}

View File

@@ -0,0 +1,19 @@
/**
* 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.view;
parcelable WindowContentFrameStats;

View File

@@ -0,0 +1,152 @@
/*
* 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.view;
import android.os.Parcel;
import android.os.Parcelable;
/**
* This class contains window content frame statistics. For example, a window content
* is rendred in frames when a view is scrolled. The frame statistics are a snapshot
* for the time interval from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
* <p>
* The key idea is that in order to provide a smooth user experience an application
* has to draw a frame at a specific time interval obtained by calling {@link
* #getRefreshPeriodNano()}. If the application does not render a frame every refresh
* period the user will see irregular UI transitions.
* </p>
* <p>
* An application posts a frame for presentation by synchronously rendering its contents
* in a buffer which is then posted or posting a buffer to which the application is
* asychronously rendering the content via GL. After the frame is posted and rendered
* (potentially asynchronosly) it is presented to the user. The time a frame was posted
* can be obtained via {@link #getFramePostedTimeNano(int)}, the time a frame content
* was rendered and ready for dsiplay (GL case) via {@link #getFrameReadyTimeNano(int)},
* and the time a frame was presented on the screen via {@link #getFramePresentedTimeNano(int)}.
* </p>
*/
public final class WindowContentFrameStats extends FrameStats implements Parcelable {
private long[] mFramesPostedTimeNano;
private long[] mFramesReadyTimeNano;
/**
* @hide
*/
public WindowContentFrameStats() {
/* do nothing */
}
/**
* Initializes this isntance.
*
* @param refreshPeriodNano The display refresh period.
* @param framesPostedTimeNano The times in milliseconds for when the frame contents were posted.
* @param framesPresentedTimeNano The times in milliseconds for when the frame contents were presented.
* @param framesReadyTimeNano The times in milliseconds for when the frame contents were ready to be presented.
*
* @hide
*/
public void init(long refreshPeriodNano, long[] framesPostedTimeNano,
long[] framesPresentedTimeNano, long[] framesReadyTimeNano) {
mRefreshPeriodNano = refreshPeriodNano;
mFramesPostedTimeNano = framesPostedTimeNano;
mFramesPresentedTimeNano = framesPresentedTimeNano;
mFramesReadyTimeNano = framesReadyTimeNano;
}
private WindowContentFrameStats(Parcel parcel) {
mRefreshPeriodNano = parcel.readLong();
mFramesPostedTimeNano = parcel.createLongArray();
mFramesPresentedTimeNano = parcel.createLongArray();
mFramesReadyTimeNano = parcel.createLongArray();
}
/**
* Get the time a frame at a given index was posted by the producer (e.g. the application).
* It is either explicitly set or defaulted to the time when the render buffer was posted.
* <p>
* <strong>Note:</strong> A frame can be posted and still it contents being rendered
* asynchronously in GL. To get the time the frame content was completely rendered and
* ready to display call {@link #getFrameReadyTimeNano(int)}.
* </p>
*
* @param index The frame index.
* @return The posted time in nanoseconds.
*/
public long getFramePostedTimeNano(int index) {
if (mFramesPostedTimeNano == null) {
throw new IndexOutOfBoundsException();
}
return mFramesPostedTimeNano[index];
}
/**
* Get the time a frame at a given index was ready for presentation.
* <p>
* <strong>Note:</strong> A frame can be posted and still it contents being rendered
* asynchronously in GL. In such a case this is the time when the frame contents were
* completely rendered.
* </p>
*
* @param index The frame index.
* @return The ready time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
* if the frame is not ready yet.
*/
public long getFrameReadyTimeNano(int index) {
if (mFramesReadyTimeNano == null) {
throw new IndexOutOfBoundsException();
}
return mFramesReadyTimeNano[index];
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(mRefreshPeriodNano);
parcel.writeLongArray(mFramesPostedTimeNano);
parcel.writeLongArray(mFramesPresentedTimeNano);
parcel.writeLongArray(mFramesReadyTimeNano);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WindowContentFrameStats[");
builder.append("frameCount:" + getFrameCount());
builder.append(", fromTimeNano:" + getStartTimeNano());
builder.append(", toTimeNano:" + getEndTimeNano());
builder.append(']');
return builder.toString();
}
public static final Parcelable.Creator<WindowContentFrameStats> CREATOR =
new Creator<WindowContentFrameStats>() {
@Override
public WindowContentFrameStats createFromParcel(Parcel parcel) {
return new WindowContentFrameStats(parcel);
}
@Override
public WindowContentFrameStats[] newArray(int size) {
return new WindowContentFrameStats[size];
}
};
}

View File

@@ -57,4 +57,6 @@ interface IAccessibilityManager {
void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
boolean touchExplorationEnabled);
IBinder getWindowToken(int windowId);
}