Merge "Support hierarchy viewer commands via DDM"
This commit is contained in:
committed by
Android (Google) Code Review
commit
281184fb86
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 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.ddm;
|
|
||||||
|
|
||||||
import android.opengl.GLUtils;
|
|
||||||
|
|
||||||
import org.apache.harmony.dalvik.ddmc.Chunk;
|
|
||||||
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
|
|
||||||
import org.apache.harmony.dalvik.ddmc.DdmServer;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class DdmHandleGlTracing extends ChunkHandler {
|
|
||||||
/** GL TRace control packets. Packet data controls starting/stopping the trace. */
|
|
||||||
public static final int CHUNK_GLTR = type("GLTR");
|
|
||||||
|
|
||||||
private static final DdmHandleGlTracing sInstance = new DdmHandleGlTracing();
|
|
||||||
|
|
||||||
/** singleton, do not instantiate. */
|
|
||||||
private DdmHandleGlTracing() {}
|
|
||||||
|
|
||||||
public static void register() {
|
|
||||||
DdmServer.registerHandler(CHUNK_GLTR, sInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connected() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disconnected() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Chunk handleChunk(Chunk request) {
|
|
||||||
int type = request.type;
|
|
||||||
|
|
||||||
if (type != CHUNK_GLTR) {
|
|
||||||
throw new RuntimeException("Unknown packet " + ChunkHandler.name(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer in = wrapChunk(request);
|
|
||||||
GLUtils.setTracingLevel(in.getInt());
|
|
||||||
return null; // empty response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,10 @@ public class DdmHandleHello extends ChunkHandler {
|
|||||||
|
|
||||||
private static DdmHandleHello mInstance = new DdmHandleHello();
|
private static DdmHandleHello mInstance = new DdmHandleHello();
|
||||||
|
|
||||||
private static final String[] NATIVE_FEATURES = new String[] { "opengl-tracing" };
|
private static final String[] FRAMEWORK_FEATURES = new String[] {
|
||||||
|
"opengl-tracing",
|
||||||
|
"view-hierarchy",
|
||||||
|
};
|
||||||
|
|
||||||
/* singleton, do not instantiate */
|
/* singleton, do not instantiate */
|
||||||
private DdmHandleHello() {}
|
private DdmHandleHello() {}
|
||||||
@@ -155,22 +158,22 @@ public class DdmHandleHello extends ChunkHandler {
|
|||||||
if (false)
|
if (false)
|
||||||
Log.v("ddm-heap", "Got feature list request");
|
Log.v("ddm-heap", "Got feature list request");
|
||||||
|
|
||||||
int size = 4 + 4 * (vmFeatures.length + NATIVE_FEATURES.length);
|
int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length);
|
||||||
for (int i = vmFeatures.length-1; i >= 0; i--)
|
for (int i = vmFeatures.length-1; i >= 0; i--)
|
||||||
size += vmFeatures[i].length() * 2;
|
size += vmFeatures[i].length() * 2;
|
||||||
for (int i = NATIVE_FEATURES.length-1; i>= 0; i--)
|
for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--)
|
||||||
size += NATIVE_FEATURES[i].length() * 2;
|
size += FRAMEWORK_FEATURES[i].length() * 2;
|
||||||
|
|
||||||
ByteBuffer out = ByteBuffer.allocate(size);
|
ByteBuffer out = ByteBuffer.allocate(size);
|
||||||
out.order(ChunkHandler.CHUNK_ORDER);
|
out.order(ChunkHandler.CHUNK_ORDER);
|
||||||
out.putInt(vmFeatures.length + NATIVE_FEATURES.length);
|
out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length);
|
||||||
for (int i = vmFeatures.length-1; i >= 0; i--) {
|
for (int i = vmFeatures.length-1; i >= 0; i--) {
|
||||||
out.putInt(vmFeatures[i].length());
|
out.putInt(vmFeatures[i].length());
|
||||||
putString(out, vmFeatures[i]);
|
putString(out, vmFeatures[i]);
|
||||||
}
|
}
|
||||||
for (int i = NATIVE_FEATURES.length-1; i >= 0; i--) {
|
for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) {
|
||||||
out.putInt(NATIVE_FEATURES[i].length());
|
out.putInt(FRAMEWORK_FEATURES[i].length());
|
||||||
putString(out, NATIVE_FEATURES[i]);
|
putString(out, FRAMEWORK_FEATURES[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Chunk(CHUNK_FEAT, out);
|
return new Chunk(CHUNK_FEAT, out);
|
||||||
|
|||||||
315
core/java/android/ddm/DdmHandleViewDebug.java
Normal file
315
core/java/android/ddm/DdmHandleViewDebug.java
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.ddm;
|
||||||
|
|
||||||
|
import android.opengl.GLUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewDebug;
|
||||||
|
import android.view.ViewRootImpl;
|
||||||
|
import android.view.WindowManagerGlobal;
|
||||||
|
|
||||||
|
import org.apache.harmony.dalvik.ddmc.Chunk;
|
||||||
|
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
|
||||||
|
import org.apache.harmony.dalvik.ddmc.DdmServer;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle various requests related to profiling / debugging of the view system.
|
||||||
|
* Support for these features are advertised via {@link DdmHandleHello}.
|
||||||
|
*/
|
||||||
|
public class DdmHandleViewDebug extends ChunkHandler {
|
||||||
|
/** Enable/Disable tracing of OpenGL calls. */
|
||||||
|
public static final int CHUNK_VUGL = type("VUGL");
|
||||||
|
|
||||||
|
/** List {@link ViewRootImpl}'s of this process. */
|
||||||
|
private static final int CHUNK_VULW = type("VULW");
|
||||||
|
|
||||||
|
/** Operation on view root, first parameter in packet should be one of VURT_* constants */
|
||||||
|
private static final int CHUNK_VURT = type("VURT");
|
||||||
|
|
||||||
|
/** Dump view hierarchy. */
|
||||||
|
private static final int VURT_DUMP_HIERARCHY = 1;
|
||||||
|
|
||||||
|
/** Capture View Layers. */
|
||||||
|
private static final int VURT_CAPTURE_LAYERS = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic View Operation, first parameter in the packet should be one of the
|
||||||
|
* VUOP_* constants below.
|
||||||
|
*/
|
||||||
|
private static final int CHUNK_VUOP = type("VUOP");
|
||||||
|
|
||||||
|
/** Capture View. */
|
||||||
|
private static final int VUOP_CAPTURE_VIEW = 1;
|
||||||
|
|
||||||
|
/** Obtain the Display List corresponding to the view. */
|
||||||
|
private static final int VUOP_DUMP_DISPLAYLIST = 2;
|
||||||
|
|
||||||
|
/** Invalidate View. */
|
||||||
|
private static final int VUOP_INVALIDATE_VIEW = 3;
|
||||||
|
|
||||||
|
/** Re-layout given view. */
|
||||||
|
private static final int VUOP_LAYOUT_VIEW = 4;
|
||||||
|
|
||||||
|
/** Profile a view. */
|
||||||
|
private static final int VUOP_PROFILE_VIEW = 5;
|
||||||
|
|
||||||
|
/** Error code indicating operation specified in chunk is invalid. */
|
||||||
|
private static final int ERR_INVALID_OP = -1;
|
||||||
|
|
||||||
|
/** Error code indicating that the parameters are invalid. */
|
||||||
|
private static final int ERR_INVALID_PARAM = -2;
|
||||||
|
|
||||||
|
private static final DdmHandleViewDebug sInstance = new DdmHandleViewDebug();
|
||||||
|
|
||||||
|
/** singleton, do not instantiate. */
|
||||||
|
private DdmHandleViewDebug() {}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
DdmServer.registerHandler(CHUNK_VUGL, sInstance);
|
||||||
|
DdmServer.registerHandler(CHUNK_VULW, sInstance);
|
||||||
|
DdmServer.registerHandler(CHUNK_VURT, sInstance);
|
||||||
|
DdmServer.registerHandler(CHUNK_VUOP, sInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connected() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnected() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk handleChunk(Chunk request) {
|
||||||
|
int type = request.type;
|
||||||
|
|
||||||
|
if (type == CHUNK_VUGL) {
|
||||||
|
return handleOpenGlTrace(request);
|
||||||
|
} else if (type == CHUNK_VULW) {
|
||||||
|
return listWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer in = wrapChunk(request);
|
||||||
|
int op = in.getInt();
|
||||||
|
|
||||||
|
View rootView = getRootView(in);
|
||||||
|
if (rootView == null) {
|
||||||
|
return createFailChunk(ERR_INVALID_PARAM, "Invalid View Root");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == CHUNK_VURT) {
|
||||||
|
if (op == VURT_DUMP_HIERARCHY)
|
||||||
|
return dumpHierarchy(rootView, in);
|
||||||
|
else if (op == VURT_CAPTURE_LAYERS)
|
||||||
|
return captureLayers(rootView);
|
||||||
|
else
|
||||||
|
return createFailChunk(ERR_INVALID_OP, "Unknown view root operation: " + op);
|
||||||
|
}
|
||||||
|
|
||||||
|
final View targetView = getTargetView(rootView, in);
|
||||||
|
if (targetView == null) {
|
||||||
|
return createFailChunk(ERR_INVALID_PARAM, "Invalid target view");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == CHUNK_VUOP) {
|
||||||
|
switch (op) {
|
||||||
|
case VUOP_CAPTURE_VIEW:
|
||||||
|
return captureView(rootView, targetView);
|
||||||
|
case VUOP_DUMP_DISPLAYLIST:
|
||||||
|
return dumpDisplayLists(rootView, targetView);
|
||||||
|
case VUOP_INVALIDATE_VIEW:
|
||||||
|
return invalidateView(rootView, targetView);
|
||||||
|
case VUOP_LAYOUT_VIEW:
|
||||||
|
return layoutView(rootView, targetView);
|
||||||
|
case VUOP_PROFILE_VIEW:
|
||||||
|
return profileView(rootView, targetView);
|
||||||
|
default:
|
||||||
|
return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unknown packet " + ChunkHandler.name(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Chunk handleOpenGlTrace(Chunk request) {
|
||||||
|
ByteBuffer in = wrapChunk(request);
|
||||||
|
GLUtils.setTracingLevel(in.getInt());
|
||||||
|
return null; // empty response
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the list of windows owned by this client. */
|
||||||
|
private Chunk listWindows() {
|
||||||
|
String[] windowNames = WindowManagerGlobal.getInstance().getViewRootNames();
|
||||||
|
|
||||||
|
int responseLength = 4; // # of windows
|
||||||
|
for (String name : windowNames) {
|
||||||
|
responseLength += 4; // length of next window name
|
||||||
|
responseLength += name.length() * 2; // window name
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer out = ByteBuffer.allocate(responseLength);
|
||||||
|
out.order(ChunkHandler.CHUNK_ORDER);
|
||||||
|
|
||||||
|
out.putInt(windowNames.length);
|
||||||
|
for (String name : windowNames) {
|
||||||
|
out.putInt(name.length());
|
||||||
|
putString(out, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Chunk(CHUNK_VULW, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
private View getRootView(ByteBuffer in) {
|
||||||
|
try {
|
||||||
|
int viewRootNameLength = in.getInt();
|
||||||
|
String viewRootName = getString(in, viewRootNameLength);
|
||||||
|
return WindowManagerGlobal.getInstance().getRootView(viewRootName);
|
||||||
|
} catch (BufferUnderflowException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private View getTargetView(View root, ByteBuffer in) {
|
||||||
|
int viewLength;
|
||||||
|
String viewName;
|
||||||
|
|
||||||
|
try {
|
||||||
|
viewLength = in.getInt();
|
||||||
|
viewName = getString(in, viewLength);
|
||||||
|
} catch (BufferUnderflowException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ViewDebug.findView(root, viewName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the view hierarchy and/or view properties starting at the provided view.
|
||||||
|
* Based on the input options, the return data may include:
|
||||||
|
* - just the view hierarchy
|
||||||
|
* - view hierarchy & the properties for each of the views
|
||||||
|
* - just the view properties for a specific view.
|
||||||
|
* TODO: Currently this only returns views starting at the root, need to fix so that
|
||||||
|
* it can return properties of any view.
|
||||||
|
*/
|
||||||
|
private Chunk dumpHierarchy(View rootView, ByteBuffer in) {
|
||||||
|
boolean skipChildren = in.getInt() > 0;
|
||||||
|
boolean includeProperties = in.getInt() > 0;
|
||||||
|
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
|
||||||
|
try {
|
||||||
|
ViewDebug.dump(rootView, skipChildren, includeProperties, b);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return createFailChunk(1, "Unexpected error while obtaining view hierarchy: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = b.toByteArray();
|
||||||
|
return new Chunk(CHUNK_VURT, data, 0, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a buffer with region details & bitmap of every single view. */
|
||||||
|
private Chunk captureLayers(View rootView) {
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
|
||||||
|
DataOutputStream dos = new DataOutputStream(b);
|
||||||
|
try {
|
||||||
|
ViewDebug.captureLayers(rootView, dos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return createFailChunk(1, "Unexpected error while obtaining view hierarchy: "
|
||||||
|
+ e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
dos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = b.toByteArray();
|
||||||
|
return new Chunk(CHUNK_VURT, data, 0, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Chunk captureView(View rootView, View targetView) {
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
|
||||||
|
try {
|
||||||
|
ViewDebug.capture(rootView, b, targetView);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return createFailChunk(1, "Unexpected error while capturing view: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = b.toByteArray();
|
||||||
|
return new Chunk(CHUNK_VUOP, data, 0, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the display lists corresponding to the provided view. */
|
||||||
|
private Chunk dumpDisplayLists(final View rootView, final View targetView) {
|
||||||
|
rootView.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ViewDebug.outputDisplayList(rootView, targetView);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invalidates provided view. */
|
||||||
|
private Chunk invalidateView(final View rootView, final View targetView) {
|
||||||
|
targetView.postInvalidate();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lays out provided view. */
|
||||||
|
private Chunk layoutView(View rootView, final View targetView) {
|
||||||
|
rootView.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
targetView.requestLayout();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Profiles provided view. */
|
||||||
|
private Chunk profileView(View rootView, final View targetView) {
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream(32 * 1024);
|
||||||
|
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(b), 32 * 1024);
|
||||||
|
try {
|
||||||
|
ViewDebug.profileViewAndChildren(targetView, bw);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return createFailChunk(1, "Unexpected error while profiling view: " + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
bw.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = b.toByteArray();
|
||||||
|
return new Chunk(CHUNK_VUOP, data, 0, data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ public class DdmRegister {
|
|||||||
DdmHandleNativeHeap.register();
|
DdmHandleNativeHeap.register();
|
||||||
DdmHandleProfiling.register();
|
DdmHandleProfiling.register();
|
||||||
DdmHandleExit.register();
|
DdmHandleExit.register();
|
||||||
DdmHandleGlTracing.register();
|
DdmHandleViewDebug.register();
|
||||||
|
|
||||||
DdmServer.registrationComplete();
|
DdmServer.registrationComplete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ public class ViewDebug {
|
|||||||
view = view.getRootView();
|
view = view.getRootView();
|
||||||
|
|
||||||
if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
|
if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
|
||||||
dump(view, clientStream);
|
dump(view, false, true, clientStream);
|
||||||
} else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) {
|
} else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) {
|
||||||
captureLayers(view, new DataOutputStream(clientStream));
|
captureLayers(view, new DataOutputStream(clientStream));
|
||||||
} else {
|
} else {
|
||||||
@@ -425,7 +425,8 @@ public class ViewDebug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static View findView(View root, String parameter) {
|
/** @hide */
|
||||||
|
public static View findView(View root, String parameter) {
|
||||||
// Look by type/hashcode
|
// Look by type/hashcode
|
||||||
if (parameter.indexOf('@') != -1) {
|
if (parameter.indexOf('@') != -1) {
|
||||||
final String[] ids = parameter.split("@");
|
final String[] ids = parameter.split("@");
|
||||||
@@ -488,7 +489,8 @@ public class ViewDebug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void profileViewAndChildren(final View view, BufferedWriter out)
|
/** @hide */
|
||||||
|
public static void profileViewAndChildren(final View view, BufferedWriter out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
profileViewAndChildren(view, out, true);
|
profileViewAndChildren(view, out, true);
|
||||||
}
|
}
|
||||||
@@ -623,7 +625,8 @@ public class ViewDebug {
|
|||||||
return duration[0];
|
return duration[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void captureLayers(View root, final DataOutputStream clientStream)
|
/** @hide */
|
||||||
|
public static void captureLayers(View root, final DataOutputStream clientStream)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -695,10 +698,21 @@ public class ViewDebug {
|
|||||||
view.getViewRootImpl().outputDisplayList(view);
|
view.getViewRootImpl().outputDisplayList(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public static void outputDisplayList(View root, View target) {
|
||||||
|
root.getViewRootImpl().outputDisplayList(target);
|
||||||
|
}
|
||||||
|
|
||||||
private static void capture(View root, final OutputStream clientStream, String parameter)
|
private static void capture(View root, final OutputStream clientStream, String parameter)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
final View captureView = findView(root, parameter);
|
final View captureView = findView(root, parameter);
|
||||||
|
capture(root, clientStream, captureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public static void capture(View root, final OutputStream clientStream, View captureView)
|
||||||
|
throws IOException {
|
||||||
Bitmap b = performViewCapture(captureView, false);
|
Bitmap b = performViewCapture(captureView, false);
|
||||||
|
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
@@ -752,14 +766,20 @@ public class ViewDebug {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dump(View root, OutputStream clientStream) throws IOException {
|
/**
|
||||||
|
* Dumps the view hierarchy starting from the given view.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static void dump(View root, boolean skipChildren, boolean includeProperties,
|
||||||
|
OutputStream clientStream) throws IOException {
|
||||||
BufferedWriter out = null;
|
BufferedWriter out = null;
|
||||||
try {
|
try {
|
||||||
out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
|
out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
|
||||||
View view = root.getRootView();
|
View view = root.getRootView();
|
||||||
if (view instanceof ViewGroup) {
|
if (view instanceof ViewGroup) {
|
||||||
ViewGroup group = (ViewGroup) view;
|
ViewGroup group = (ViewGroup) view;
|
||||||
dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
|
dumpViewHierarchy(group.getContext(), group, out, 0,
|
||||||
|
skipChildren, includeProperties);
|
||||||
}
|
}
|
||||||
out.write("DONE.");
|
out.write("DONE.");
|
||||||
out.newLine();
|
out.newLine();
|
||||||
@@ -804,9 +824,13 @@ public class ViewDebug {
|
|||||||
return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
|
return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
|
private static void dumpViewHierarchy(Context context, ViewGroup group,
|
||||||
BufferedWriter out, int level) {
|
BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) {
|
||||||
if (!dumpViewWithProperties(context, group, out, level)) {
|
if (!dumpView(context, group, out, level, includeProperties)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipChildren) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,9 +838,10 @@ public class ViewDebug {
|
|||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
final View view = group.getChildAt(i);
|
final View view = group.getChildAt(i);
|
||||||
if (view instanceof ViewGroup) {
|
if (view instanceof ViewGroup) {
|
||||||
dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
|
dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren,
|
||||||
|
includeProperties);
|
||||||
} else {
|
} else {
|
||||||
dumpViewWithProperties(context, view, out, level + 1);
|
dumpView(context, view, out, level + 1, includeProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (group instanceof HierarchyHandler) {
|
if (group instanceof HierarchyHandler) {
|
||||||
@@ -824,8 +849,8 @@ public class ViewDebug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean dumpViewWithProperties(Context context, View view,
|
private static boolean dumpView(Context context, View view,
|
||||||
BufferedWriter out, int level) {
|
BufferedWriter out, int level, boolean includeProperties) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < level; i++) {
|
for (int i = 0; i < level; i++) {
|
||||||
@@ -835,7 +860,9 @@ public class ViewDebug {
|
|||||||
out.write('@');
|
out.write('@');
|
||||||
out.write(Integer.toHexString(view.hashCode()));
|
out.write(Integer.toHexString(view.hashCode()));
|
||||||
out.write(' ');
|
out.write(' ');
|
||||||
dumpViewProperties(context, view, out);
|
if (includeProperties) {
|
||||||
|
dumpViewProperties(context, view, out);
|
||||||
|
}
|
||||||
out.newLine();
|
out.newLine();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("View", "Error while dumping hierarchy tree");
|
Log.w("View", "Error while dumping hierarchy tree");
|
||||||
|
|||||||
@@ -160,6 +160,29 @@ public final class WindowManagerGlobal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getViewRootNames() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mRoots == null) return new String[0];
|
||||||
|
String[] mViewRoots = new String[mRoots.length];
|
||||||
|
int i = 0;
|
||||||
|
for (ViewRootImpl root : mRoots) {
|
||||||
|
mViewRoots[i++] = getWindowName(root);
|
||||||
|
}
|
||||||
|
return mViewRoots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getRootView(String name) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mRoots == null) return null;
|
||||||
|
for (ViewRootImpl root : mRoots) {
|
||||||
|
if (name.equals(getWindowName(root))) return root.getView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void addView(View view, ViewGroup.LayoutParams params,
|
public void addView(View view, ViewGroup.LayoutParams params,
|
||||||
Display display, Window parentWindow) {
|
Display display, Window parentWindow) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user