Loading protos/view_capture.proto +25 −22 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ option java_outer_classname = "ViewCaptureData"; message ExportedData { repeated FrameData frameData = 1; repeated string classname = 2; } message FrameData { Loading @@ -31,26 +32,28 @@ message FrameData { } message ViewNode { optional string classname = 1; optional string id = 2; optional int32 left = 3; optional int32 top = 4; optional int32 width = 5; optional int32 height = 6; optional int32 scrollX = 7; optional int32 scrollY = 8; optional float translationX = 9; optional float translationY = 10; optional float scaleX = 11 [default = 1]; optional float scaleY = 12 [default = 1]; optional float alpha = 13 [default = 1]; optional bool willNotDraw = 14; optional bool clipChildren = 15; optional int32 visibility = 16; repeated ViewNode children = 17; optional float elevation = 18; optional int32 classname_index = 1; optional int32 hashcode = 2; repeated ViewNode children = 3; optional string id = 4; optional int32 left = 5; optional int32 top = 6; optional int32 width = 7; optional int32 height = 8; optional int32 scrollX = 9; optional int32 scrollY = 10; optional float translationX = 11; optional float translationY = 12; optional float scaleX = 13 [default = 1]; optional float scaleY = 14 [default = 1]; optional float alpha = 15 [default = 1]; optional bool willNotDraw = 16; optional bool clipChildren = 17; optional int32 visibility = 18; optional float elevation = 19; } src/com/android/launcher3/Launcher.java +11 −9 Original line number Diff line number Diff line Loading @@ -1491,9 +1491,9 @@ public class Launcher extends StatefulActivity<LauncherState> if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { View root = getDragLayer().getRootView(); if (mViewCapture != null) { root.getViewTreeObserver().removeOnDrawListener(mViewCapture); mViewCapture.detach(); } mViewCapture = new ViewCapture(root); mViewCapture = new ViewCapture(getWindow()); mViewCapture.attach(); } } Loading @@ -1501,6 +1501,10 @@ public class Launcher extends StatefulActivity<LauncherState> @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mViewCapture != null) { mViewCapture.detach(); mViewCapture = null; } mOverlayManager.onDetachedFromWindow(); closeContextMenu(); } Loading Loading @@ -2981,6 +2985,7 @@ public class Launcher extends StatefulActivity<LauncherState> */ @Override public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { SafeCloseable viewDump = mViewCapture == null ? null : mViewCapture.beginDump(writer, fd); super.dump(prefix, fd, writer, args); if (args.length > 0 && TextUtils.equals(args[0], "--all")) { Loading Loading @@ -3015,19 +3020,16 @@ public class Launcher extends StatefulActivity<LauncherState> writer.println(prefix + "\tmRotationHelper: " + mRotationHelper); writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening()); if (mViewCapture != null) { writer.print(prefix + "\tmViewCapture: "); writer.flush(); mViewCapture.dump(fd); writer.println(); } // Extra logging for general debugging mDragLayer.dump(prefix, writer); mStateManager.dump(prefix, writer); mPopupDataProvider.dump(prefix, writer); mDeviceProfile.dump(this, prefix, writer); if (viewDump != null) { viewDump.close(); } try { FileLog.flushAll(writer); } catch (Exception e) { Loading src/com/android/launcher3/util/ViewCapture.java +69 −24 Original line number Diff line number Diff line Loading @@ -15,18 +15,23 @@ */ package com.android.launcher3.util; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static java.util.stream.Collectors.toList; import android.content.res.Resources; import android.os.Handler; import android.os.Message; import android.os.Trace; import android.text.TextUtils; import android.util.Base64; import android.util.Base64OutputStream; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnDrawListener; import android.view.Window; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; Loading @@ -38,7 +43,10 @@ import com.android.launcher3.view.ViewCaptureData.ViewNode; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.Future; import java.util.zip.GZIPOutputStream; /** * Utility class for capturing view data every frame Loading @@ -53,6 +61,7 @@ public class ViewCapture implements OnDrawListener { // Launcher. This allows the first free frames avoid object allocation during view capture. private static final int INIT_POOL_SIZE = 300; private final Window mWindow; private final View mRoot; private final Resources mResources; Loading @@ -67,11 +76,12 @@ public class ViewCapture implements OnDrawListener { private ViewRef mPool = new ViewRef(); /** * @param root the root view for the capture data * @param window the window for the capture data */ public ViewCapture(View root) { mRoot = root; mResources = root.getResources(); public ViewCapture(Window window) { mWindow = window; mRoot = mWindow.getDecorView(); mResources = mRoot.getResources(); mHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::captureViewPropertiesBg); } Loading @@ -82,6 +92,14 @@ public class ViewCapture implements OnDrawListener { mHandler.post(this::initPool); } /** * Removes a previously attached ViewCapture from the root */ public void detach() { mHandler.post(() -> MAIN_EXECUTOR.execute( () -> mRoot.getViewTreeObserver().removeOnDrawListener(this))); } @Override public void onDraw() { Trace.beginSection("view_capture"); Loading Loading @@ -139,7 +157,7 @@ public class ViewCapture implements OnDrawListener { } mNodesBg[mFrameIndexBg] = result; ViewRef end = last; Executors.MAIN_EXECUTOR.execute(() -> addToPool(start, end)); MAIN_EXECUTOR.execute(() -> addToPool(start, end)); return true; } Loading @@ -160,7 +178,7 @@ public class ViewCapture implements OnDrawListener { } ViewRef end = current; Executors.MAIN_EXECUTOR.execute(() -> { MAIN_EXECUTOR.execute(() -> { addToPool(start, end); if (mRoot.isAttachedToWindow()) { mRoot.getViewTreeObserver().addOnDrawListener(this); Loading @@ -168,38 +186,58 @@ public class ViewCapture implements OnDrawListener { }); } private String getName() { String title = mWindow.getAttributes().getTitle().toString(); return TextUtils.isEmpty(title) ? mWindow.toString() : title; } /** * Creates a proto of all the data captured so far. * Starts the dump process which is completed on closing the returned object. */ public void dump(FileDescriptor out) { public SafeCloseable beginDump(PrintWriter writer, FileDescriptor out) { Future<ExportedData> task = UI_HELPER_EXECUTOR.submit(this::dumpToProto); return () -> { writer.println(); writer.println(" ContinuousViewCapture:"); writer.println(" window " + getName() + ":"); writer.println(" pkg:" + mRoot.getContext().getPackageName()); writer.print(" data:"); writer.flush(); try (OutputStream os = new FileOutputStream(out)) { ExportedData data = task.get(); Base64OutputStream encodedOS = new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP)); data.writeTo(encodedOS); encodedOS.close(); os.flush(); } catch (Exception e) { Log.e(TAG, "Error capturing proto", e); } writer.println(); writer.println("--end--"); }; } @WorkerThread private ExportedData dumpToProto() { ExportedData.Builder dataBuilder = ExportedData.newBuilder(); Resources res = mResources; ArrayList<Class> classList = new ArrayList<>(); int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE; for (int i = size - 1; i >= 0; i--) { int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE; ViewNode.Builder nodeBuilder = ViewNode.newBuilder(); mNodesBg[index].toProto(res, nodeBuilder); mNodesBg[index].toProto(res, classList, nodeBuilder); dataBuilder.addFrameData(FrameData.newBuilder() .setNode(nodeBuilder) .setTimestamp(mFrameTimesBg[index])); } return dataBuilder.build(); return dataBuilder .addAllClassname(classList.stream().map(Class::getName).collect(toList())) .build(); } private ViewRef captureViewTree(View view, ViewRef start) { Loading Loading @@ -278,10 +316,10 @@ public class ViewCapture implements OnDrawListener { /** * Converts the data to the proto representation and returns the next property ref * at the end of the iteration. * @param res * @return */ public ViewPropertyRef toProto(Resources res, ViewNode.Builder outBuilder) { public ViewPropertyRef toProto(Resources res, ArrayList<Class> classList, ViewNode.Builder outBuilder) { String resolvedId; if (id >= 0) { try { Loading @@ -292,7 +330,14 @@ public class ViewCapture implements OnDrawListener { } else { resolvedId = "NO_ID"; } outBuilder.setClassname(clazz.getName() + "@" + hashCode) int classnameIndex = classList.indexOf(clazz); if (classnameIndex < 0) { classnameIndex = classList.size(); classList.add(clazz); } outBuilder .setClassnameIndex(classnameIndex) .setHashcode(hashCode) .setId(resolvedId) .setLeft(left) .setTop(top) Loading @@ -311,7 +356,7 @@ public class ViewCapture implements OnDrawListener { ViewPropertyRef result = next; for (int i = 0; (i < childCount) && (result != null); i++) { ViewNode.Builder childBuilder = ViewNode.newBuilder(); result = result.toProto(res, childBuilder); result = result.toProto(res, classList, childBuilder); outBuilder.addChildren(childBuilder); } return result; Loading Loading
protos/view_capture.proto +25 −22 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ option java_outer_classname = "ViewCaptureData"; message ExportedData { repeated FrameData frameData = 1; repeated string classname = 2; } message FrameData { Loading @@ -31,26 +32,28 @@ message FrameData { } message ViewNode { optional string classname = 1; optional string id = 2; optional int32 left = 3; optional int32 top = 4; optional int32 width = 5; optional int32 height = 6; optional int32 scrollX = 7; optional int32 scrollY = 8; optional float translationX = 9; optional float translationY = 10; optional float scaleX = 11 [default = 1]; optional float scaleY = 12 [default = 1]; optional float alpha = 13 [default = 1]; optional bool willNotDraw = 14; optional bool clipChildren = 15; optional int32 visibility = 16; repeated ViewNode children = 17; optional float elevation = 18; optional int32 classname_index = 1; optional int32 hashcode = 2; repeated ViewNode children = 3; optional string id = 4; optional int32 left = 5; optional int32 top = 6; optional int32 width = 7; optional int32 height = 8; optional int32 scrollX = 9; optional int32 scrollY = 10; optional float translationX = 11; optional float translationY = 12; optional float scaleX = 13 [default = 1]; optional float scaleY = 14 [default = 1]; optional float alpha = 15 [default = 1]; optional bool willNotDraw = 16; optional bool clipChildren = 17; optional int32 visibility = 18; optional float elevation = 19; }
src/com/android/launcher3/Launcher.java +11 −9 Original line number Diff line number Diff line Loading @@ -1491,9 +1491,9 @@ public class Launcher extends StatefulActivity<LauncherState> if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { View root = getDragLayer().getRootView(); if (mViewCapture != null) { root.getViewTreeObserver().removeOnDrawListener(mViewCapture); mViewCapture.detach(); } mViewCapture = new ViewCapture(root); mViewCapture = new ViewCapture(getWindow()); mViewCapture.attach(); } } Loading @@ -1501,6 +1501,10 @@ public class Launcher extends StatefulActivity<LauncherState> @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mViewCapture != null) { mViewCapture.detach(); mViewCapture = null; } mOverlayManager.onDetachedFromWindow(); closeContextMenu(); } Loading Loading @@ -2981,6 +2985,7 @@ public class Launcher extends StatefulActivity<LauncherState> */ @Override public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { SafeCloseable viewDump = mViewCapture == null ? null : mViewCapture.beginDump(writer, fd); super.dump(prefix, fd, writer, args); if (args.length > 0 && TextUtils.equals(args[0], "--all")) { Loading Loading @@ -3015,19 +3020,16 @@ public class Launcher extends StatefulActivity<LauncherState> writer.println(prefix + "\tmRotationHelper: " + mRotationHelper); writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening()); if (mViewCapture != null) { writer.print(prefix + "\tmViewCapture: "); writer.flush(); mViewCapture.dump(fd); writer.println(); } // Extra logging for general debugging mDragLayer.dump(prefix, writer); mStateManager.dump(prefix, writer); mPopupDataProvider.dump(prefix, writer); mDeviceProfile.dump(this, prefix, writer); if (viewDump != null) { viewDump.close(); } try { FileLog.flushAll(writer); } catch (Exception e) { Loading
src/com/android/launcher3/util/ViewCapture.java +69 −24 Original line number Diff line number Diff line Loading @@ -15,18 +15,23 @@ */ package com.android.launcher3.util; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static java.util.stream.Collectors.toList; import android.content.res.Resources; import android.os.Handler; import android.os.Message; import android.os.Trace; import android.text.TextUtils; import android.util.Base64; import android.util.Base64OutputStream; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnDrawListener; import android.view.Window; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; Loading @@ -38,7 +43,10 @@ import com.android.launcher3.view.ViewCaptureData.ViewNode; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.Future; import java.util.zip.GZIPOutputStream; /** * Utility class for capturing view data every frame Loading @@ -53,6 +61,7 @@ public class ViewCapture implements OnDrawListener { // Launcher. This allows the first free frames avoid object allocation during view capture. private static final int INIT_POOL_SIZE = 300; private final Window mWindow; private final View mRoot; private final Resources mResources; Loading @@ -67,11 +76,12 @@ public class ViewCapture implements OnDrawListener { private ViewRef mPool = new ViewRef(); /** * @param root the root view for the capture data * @param window the window for the capture data */ public ViewCapture(View root) { mRoot = root; mResources = root.getResources(); public ViewCapture(Window window) { mWindow = window; mRoot = mWindow.getDecorView(); mResources = mRoot.getResources(); mHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::captureViewPropertiesBg); } Loading @@ -82,6 +92,14 @@ public class ViewCapture implements OnDrawListener { mHandler.post(this::initPool); } /** * Removes a previously attached ViewCapture from the root */ public void detach() { mHandler.post(() -> MAIN_EXECUTOR.execute( () -> mRoot.getViewTreeObserver().removeOnDrawListener(this))); } @Override public void onDraw() { Trace.beginSection("view_capture"); Loading Loading @@ -139,7 +157,7 @@ public class ViewCapture implements OnDrawListener { } mNodesBg[mFrameIndexBg] = result; ViewRef end = last; Executors.MAIN_EXECUTOR.execute(() -> addToPool(start, end)); MAIN_EXECUTOR.execute(() -> addToPool(start, end)); return true; } Loading @@ -160,7 +178,7 @@ public class ViewCapture implements OnDrawListener { } ViewRef end = current; Executors.MAIN_EXECUTOR.execute(() -> { MAIN_EXECUTOR.execute(() -> { addToPool(start, end); if (mRoot.isAttachedToWindow()) { mRoot.getViewTreeObserver().addOnDrawListener(this); Loading @@ -168,38 +186,58 @@ public class ViewCapture implements OnDrawListener { }); } private String getName() { String title = mWindow.getAttributes().getTitle().toString(); return TextUtils.isEmpty(title) ? mWindow.toString() : title; } /** * Creates a proto of all the data captured so far. * Starts the dump process which is completed on closing the returned object. */ public void dump(FileDescriptor out) { public SafeCloseable beginDump(PrintWriter writer, FileDescriptor out) { Future<ExportedData> task = UI_HELPER_EXECUTOR.submit(this::dumpToProto); return () -> { writer.println(); writer.println(" ContinuousViewCapture:"); writer.println(" window " + getName() + ":"); writer.println(" pkg:" + mRoot.getContext().getPackageName()); writer.print(" data:"); writer.flush(); try (OutputStream os = new FileOutputStream(out)) { ExportedData data = task.get(); Base64OutputStream encodedOS = new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP)); data.writeTo(encodedOS); encodedOS.close(); os.flush(); } catch (Exception e) { Log.e(TAG, "Error capturing proto", e); } writer.println(); writer.println("--end--"); }; } @WorkerThread private ExportedData dumpToProto() { ExportedData.Builder dataBuilder = ExportedData.newBuilder(); Resources res = mResources; ArrayList<Class> classList = new ArrayList<>(); int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE; for (int i = size - 1; i >= 0; i--) { int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE; ViewNode.Builder nodeBuilder = ViewNode.newBuilder(); mNodesBg[index].toProto(res, nodeBuilder); mNodesBg[index].toProto(res, classList, nodeBuilder); dataBuilder.addFrameData(FrameData.newBuilder() .setNode(nodeBuilder) .setTimestamp(mFrameTimesBg[index])); } return dataBuilder.build(); return dataBuilder .addAllClassname(classList.stream().map(Class::getName).collect(toList())) .build(); } private ViewRef captureViewTree(View view, ViewRef start) { Loading Loading @@ -278,10 +316,10 @@ public class ViewCapture implements OnDrawListener { /** * Converts the data to the proto representation and returns the next property ref * at the end of the iteration. * @param res * @return */ public ViewPropertyRef toProto(Resources res, ViewNode.Builder outBuilder) { public ViewPropertyRef toProto(Resources res, ArrayList<Class> classList, ViewNode.Builder outBuilder) { String resolvedId; if (id >= 0) { try { Loading @@ -292,7 +330,14 @@ public class ViewCapture implements OnDrawListener { } else { resolvedId = "NO_ID"; } outBuilder.setClassname(clazz.getName() + "@" + hashCode) int classnameIndex = classList.indexOf(clazz); if (classnameIndex < 0) { classnameIndex = classList.size(); classList.add(clazz); } outBuilder .setClassnameIndex(classnameIndex) .setHashcode(hashCode) .setId(resolvedId) .setLeft(left) .setTop(top) Loading @@ -311,7 +356,7 @@ public class ViewCapture implements OnDrawListener { ViewPropertyRef result = next; for (int i = 0; (i < childCount) && (result != null); i++) { ViewNode.Builder childBuilder = ViewNode.newBuilder(); result = result.toProto(res, childBuilder); result = result.toProto(res, classList, childBuilder); outBuilder.addChildren(childBuilder); } return result; Loading