diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-11 12:11:56 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-11 12:11:56 -0700 |
commit | c39a6e0c51e182338deb8b63d07933b585134929 (patch) | |
tree | e55fc5bd38b1eb8fb4851a0fe1cc264a7fe2f245 /core/java/android/view | |
parent | b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54 (diff) | |
download | frameworks_base-c39a6e0c51e182338deb8b63d07933b585134929.zip frameworks_base-c39a6e0c51e182338deb8b63d07933b585134929.tar.gz frameworks_base-c39a6e0c51e182338deb8b63d07933b585134929.tar.bz2 |
auto import from //branches/cupcake/...@137873
Diffstat (limited to 'core/java/android/view')
-rw-r--r-- | core/java/android/view/View.java | 19 | ||||
-rw-r--r-- | core/java/android/view/ViewDebug.java | 376 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 10 | ||||
-rw-r--r-- | core/java/android/view/inputmethod/InputMethodInfo.java | 8 | ||||
-rw-r--r-- | core/java/android/view/inputmethod/InputMethodManager.java | 1 |
5 files changed, 332 insertions, 82 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d78320a..c3e00c4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1511,8 +1511,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { @ViewDebug.ExportedProperty int mUserPaddingBottom; - private int mOldWidthMeasureSpec = Integer.MIN_VALUE; - private int mOldHeightMeasureSpec = Integer.MIN_VALUE; + /** + * @hide + */ + int mOldWidthMeasureSpec = Integer.MIN_VALUE; + /** + * @hide + */ + int mOldHeightMeasureSpec = Integer.MIN_VALUE; private Resources mResources = null; @@ -2661,9 +2667,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @attr ref android.R.styleable#View_visibility */ @ViewDebug.ExportedProperty(mapping = { - @ViewDebug.IntToString(from = 0, to = "VISIBLE"), - @ViewDebug.IntToString(from = 4, to = "INVISIBLE"), - @ViewDebug.IntToString(from = 8, to = "GONE") + @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), + @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), + @ViewDebug.IntToString(from = GONE, to = "GONE") }) public int getVisibility() { return mViewFlags & VISIBILITY_MASK; @@ -3291,8 +3297,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set */ private static void captureViewInfo(String subTag, View v) { - if (v == null || - SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) { + if (v == null || SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) { return; } ViewDebug.dumpCapturedView(subTag, v); diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 883c7bd..0a043bd 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -17,9 +17,12 @@ package android.view; import android.util.Log; +import android.util.DisplayMetrics; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.os.Environment; +import android.os.Debug; import java.io.File; import java.io.BufferedWriter; @@ -43,6 +46,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.AccessibleObject; /** * Various debugging/tracing tools related to {@link View} and the view hierarchy. @@ -73,7 +77,7 @@ public class ViewDebug { * when it is set, we log key events, touch/motion and trackball events */ static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; - + /** * This annotation can be used to mark fields and methods to be dumped by * the view server. Only non-void methods with no arguments can be annotated @@ -113,6 +117,27 @@ public class ViewDebug { IntToString[] mapping() default { }; /** + * A mapping can be defined to map array indices to specific strings. + * A mapping can be used to see human readable values for the indices + * of an array: + * + * <pre> + * @ViewDebug.ExportedProperty(mapping = { + * @ViewDebug.IntToString(from = 0, to = "INVALID"), + * @ViewDebug.IntToString(from = 1, to = "FIRST"), + * @ViewDebug.IntToString(from = 2, to = "SECOND") + * }) + * private int[] mElements; + * <pre> + * + * @return An array of int to String mappings + * + * @see android.view.ViewDebug.IntToString + * @see #mapping() + */ + IntToString[] indexMapping() default { }; + + /** * When deep export is turned on, this property is not dumped. Instead, the * properties contained in this property are dumped. Each child property * is prefixed with the name of this property. @@ -187,10 +212,12 @@ public class ViewDebug { private static final String REMOTE_COMMAND_DUMP = "DUMP"; private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; + private static final String REMOTE_PROFILE = "PROFILE"; private static HashMap<Class<?>, Field[]> sFieldsForClasses; private static HashMap<Class<?>, Method[]> sMethodsForClasses; - + private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; + /** * Defines the type of hierarhcy trace to output to the hierarchy traces file. */ @@ -347,6 +374,7 @@ public class ViewDebug { } File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); + //noinspection ResultOfMethodCallIgnored recyclerDump.mkdirs(); recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); @@ -450,6 +478,7 @@ public class ViewDebug { } File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); + //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, prefix + ".traces"); @@ -497,6 +526,7 @@ public class ViewDebug { sHierarchyTraces = null; File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); + //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); @@ -538,32 +568,41 @@ public class ViewDebug { invalidate(view, params[0]); } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { requestLayout(view, params[0]); + } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { + profile(view, clientStream, params[0]); } } } - private static View findViewByHashCode(View root, String parameter) { - final String[] ids = parameter.split("@"); - final String className = ids[0]; - final int hashCode = Integer.parseInt(ids[1], 16); + private static View findView(View root, String parameter) { + // Look by type/hashcode + if (parameter.indexOf('@') != -1) { + final String[] ids = parameter.split("@"); + final String className = ids[0]; + final int hashCode = Integer.parseInt(ids[1], 16); - View view = root.getRootView(); - if (view instanceof ViewGroup) { - return findView((ViewGroup) view, className, hashCode); + View view = root.getRootView(); + if (view instanceof ViewGroup) { + return findView((ViewGroup) view, className, hashCode); + } + } else { + // Look by id + final int id = root.getResources().getIdentifier(parameter, null, null); + return root.getRootView().findViewById(id); } return null; } private static void invalidate(View root, String parameter) { - final View view = findViewByHashCode(root, parameter); + final View view = findView(root, parameter); if (view != null) { view.postInvalidate(); } } private static void requestLayout(View root, String parameter) { - final View view = findViewByHashCode(root, parameter); + final View view = findView(root, parameter); if (view != null) { root.post(new Runnable() { public void run() { @@ -573,19 +612,139 @@ public class ViewDebug { } } - private static void capture(View root, final OutputStream clientStream, String parameter) + private static void profile(View root, OutputStream clientStream, String parameter) throws IOException { + final View view = findView(root, parameter); + BufferedWriter out = null; + try { + out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); + + if (view != null) { + final long durationMeasure = profileViewOperation(view, new ViewOperation<Void>() { + public Void[] pre() { + forceLayout(view); + return null; + } + + private void forceLayout(View view) { + view.forceLayout(); + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + final int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + forceLayout(group.getChildAt(i)); + } + } + } + + public void run(Void... data) { + view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); + } + + public void post(Void... data) { + } + }); + + final long durationLayout = profileViewOperation(view, new ViewOperation<Void>() { + public Void[] pre() { + return null; + } + + public void run(Void... data) { + view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); + } + + public void post(Void... data) { + } + }); + + final long durationDraw = profileViewOperation(view, new ViewOperation<Object>() { + public Object[] pre() { + final DisplayMetrics metrics = view.getResources().getDisplayMetrics(); + final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels, + metrics.heightPixels, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmap); + return new Object[] { bitmap, canvas }; + } + + public void run(Object... data) { + view.draw((Canvas) data[1]); + } + + public void post(Object... data) { + ((Bitmap) data[0]).recycle(); + } + }); + + out.write(String.valueOf(durationMeasure)); + out.write(' '); + out.write(String.valueOf(durationLayout)); + out.write(' '); + out.write(String.valueOf(durationDraw)); + out.newLine(); + } else { + out.write("-1 -1 -1"); + out.newLine(); + } + } catch (Exception e) { + android.util.Log.w("View", "Problem profiling the view:", e); + } finally { + if (out != null) { + out.close(); + } + } + } + + interface ViewOperation<T> { + T[] pre(); + void run(T... data); + void post(T... data); + } + + private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { final CountDownLatch latch = new CountDownLatch(1); - final View captureView = findViewByHashCode(root, parameter); + final long[] duration = new long[1]; + + view.post(new Runnable() { + public void run() { + try { + T[] data = operation.pre(); + long start = Debug.threadCpuTimeNanos(); + operation.run(data); + duration[0] = Debug.threadCpuTimeNanos() - start; + operation.post(data); + } finally { + latch.countDown(); + } + } + }); + + try { + latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Log.w("View", "Could not complete the profiling of the view " + view); + Thread.currentThread().interrupt(); + return -1; + } + + return duration[0]; + } + + private static void capture(View root, final OutputStream clientStream, String parameter) + throws IOException { + + final View captureView = findView(root, parameter); if (captureView != null) { + final CountDownLatch latch = new CountDownLatch(1); final Bitmap[] cache = new Bitmap[1]; final boolean hasCache = captureView.isDrawingCacheEnabled(); final boolean willNotCache = captureView.willNotCacheDrawing(); if (willNotCache) { + // TODO: Should happen on the UI thread captureView.setWillNotCacheDrawing(false); } @@ -619,12 +778,15 @@ public class ViewDebug { } } } catch (InterruptedException e) { - Log.w("View", "Could not complete the capture of the view " + captureView); + Log.w("View", "Could not complete the capture of the view " + captureView); + Thread.currentThread().interrupt(); } finally { if (willNotCache) { + // TODO: Should happen on the UI thread captureView.setWillNotCacheDrawing(true); } if (!hasCache) { + // TODO: Should happen on the UI thread captureView.destroyDrawingCache(); } } @@ -642,6 +804,8 @@ public class ViewDebug { } out.write("DONE."); out.newLine(); + } catch (Exception e) { + android.util.Log.w("View", "Problem dumping the view:", e); } finally { if (out != null) { out.close(); @@ -713,7 +877,12 @@ public class ViewDebug { if (sFieldsForClasses == null) { sFieldsForClasses = new HashMap<Class<?>, Field[]>(); } + if (sAnnotations == null) { + sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); + } + final HashMap<Class<?>, Field[]> map = sFieldsForClasses; + final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; Field[] fields = map.get(klass); if (fields != null) { @@ -729,6 +898,7 @@ public class ViewDebug { if (field.isAnnotationPresent(ExportedProperty.class)) { field.setAccessible(true); foundFields.add(field); + annotations.put(field, field.getAnnotation(ExportedProperty.class)); } } @@ -740,9 +910,14 @@ public class ViewDebug { private static Method[] getExportedPropertyMethods(Class<?> klass) { if (sMethodsForClasses == null) { - sMethodsForClasses = new HashMap<Class<?>, Method[]>(); + sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); + } + if (sAnnotations == null) { + sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); } + final HashMap<Class<?>, Method[]> map = sMethodsForClasses; + final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; Method[] methods = map.get(klass); if (methods != null) { @@ -756,10 +931,11 @@ public class ViewDebug { for (int i = 0; i < count; i++) { final Method method = methods[i]; if (method.getParameterTypes().length == 0 && - method.isAnnotationPresent(ExportedProperty.class) && - method.getReturnType() != Void.class) { + method.isAnnotationPresent(ExportedProperty.class) && + method.getReturnType() != Void.class) { method.setAccessible(true); foundMethods.add(method); + annotations.put(method, method.getAnnotation(ExportedProperty.class)); } } @@ -799,20 +975,10 @@ public class ViewDebug { final Class<?> returnType = method.getReturnType(); if (returnType == int.class) { - ExportedProperty property = method.getAnnotation(ExportedProperty.class); + final ExportedProperty property = sAnnotations.get(method); if (property.resolveId() && view instanceof View) { - final Resources resources = ((View) view).getContext().getResources(); final int id = (Integer) methodValue; - if (id >= 0) { - try { - methodValue = resources.getResourceTypeName(id) + '/' + - resources.getResourceEntryName(id); - } catch (Resources.NotFoundException e) { - methodValue = "UNKNOWN"; - } - } else { - methodValue = "NO_ID"; - } + methodValue = resolveId(view, id); } else { final IntToString[] mapping = property.mapping(); if (mapping.length > 0) { @@ -833,28 +999,22 @@ public class ViewDebug { } } } + } else if (returnType == int[].class) { + final ExportedProperty property = sAnnotations.get(method); + final int[] array = (int[]) methodValue; + final String valuePrefix = prefix + method.getName() + '_'; + final String suffix = "()"; + + exportUnrolledArray(view, out, property, array, valuePrefix, suffix); } else if (!returnType.isPrimitive()) { - ExportedProperty property = method.getAnnotation(ExportedProperty.class); + final ExportedProperty property = sAnnotations.get(method); if (property.deepExport()) { dumpViewProperties(methodValue, out, prefix + property.prefix()); continue; } } - out.write(prefix); - out.write(method.getName()); - out.write("()="); - - if (methodValue != null) { - final String value = methodValue.toString().replace("\n", "\\n"); - out.write(String.valueOf(value.length())); - out.write(","); - out.write(value); - } else { - out.write("4,null"); - } - - out.write(' '); + writeEntry(out, prefix, method.getName(), "()", methodValue); } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } @@ -875,20 +1035,10 @@ public class ViewDebug { final Class<?> type = field.getType(); if (type == int.class) { - ExportedProperty property = field.getAnnotation(ExportedProperty.class); + final ExportedProperty property = sAnnotations.get(field); if (property.resolveId() && view instanceof View) { - final Resources resources = ((View) view).getContext().getResources(); final int id = field.getInt(view); - if (id >= 0) { - try { - fieldValue = resources.getResourceTypeName(id) + '/' + - resources.getResourceEntryName(id); - } catch (Resources.NotFoundException e) { - fieldValue = "UNKNOWN"; - } - } else { - fieldValue = "NO_ID"; - } + fieldValue = resolveId(view, id); } else { final IntToString[] mapping = property.mapping(); if (mapping.length > 0) { @@ -907,8 +1057,18 @@ public class ViewDebug { } } } + } else if (type == int[].class) { + final ExportedProperty property = sAnnotations.get(field); + final int[] array = (int[]) field.get(view); + final String valuePrefix = prefix + field.getName() + '_'; + final String suffix = ""; + + exportUnrolledArray(view, out, property, array, valuePrefix, suffix); + + // We exit here! + return; } else if (!type.isPrimitive()) { - ExportedProperty property = field.getAnnotation(ExportedProperty.class); + final ExportedProperty property = sAnnotations.get(field); if (property.deepExport()) { dumpViewProperties(field.get(view), out, prefix + property.prefix()); continue; @@ -917,24 +1077,100 @@ public class ViewDebug { if (fieldValue == null) { fieldValue = field.get(view); - } + } - out.write(prefix); - out.write(field.getName()); - out.write('='); + writeEntry(out, prefix, field.getName(), "", fieldValue); + } catch (IllegalAccessException e) { + } + } + } - if (fieldValue != null) { - final String value = fieldValue.toString().replace("\n", "\\n"); - out.write(String.valueOf(value.length())); - out.write(","); - out.write(value); - } else { - out.write("4,null"); + private static void writeEntry(BufferedWriter out, String prefix, String name, + String suffix, Object value) throws IOException { + + out.write(prefix); + out.write(name); + out.write(suffix); + out.write("="); + writeValue(out, value); + out.write(' '); + } + + private static void exportUnrolledArray(Object view, BufferedWriter out, + ExportedProperty property, int[] array, String prefix, String suffix) + throws IOException { + + final IntToString[] indexMapping = property.indexMapping(); + final boolean hasIndexMapping = indexMapping.length > 0; + + final IntToString[] mapping = property.mapping(); + final boolean hasMapping = mapping.length > 0; + + final boolean resolveId = property.resolveId() && view instanceof View; + final int valuesCount = array.length; + + for (int j = 0; j < valuesCount; j++) { + String name; + String value; + + final int intValue = array[j]; + + name = String.valueOf(j); + if (hasIndexMapping) { + int mappingCount = indexMapping.length; + for (int k = 0; k < mappingCount; k++) { + final IntToString mapped = indexMapping[k]; + if (mapped.from() == j) { + name = mapped.to(); + break; + } } + } - out.write(' '); - } catch (IllegalAccessException e) { + value = String.valueOf(intValue); + if (hasMapping) { + int mappingCount = mapping.length; + for (int k = 0; k < mappingCount; k++) { + final IntToString mapped = mapping[k]; + if (mapped.from() == intValue) { + value = mapped.to(); + break; + } + } + } + + if (resolveId) { + value = (String) resolveId(view, intValue); } + + writeEntry(out, prefix, name, suffix, value); + } + } + + private static Object resolveId(Object view, int id) { + Object fieldValue; + final Resources resources = ((View) view).getContext().getResources(); + if (id >= 0) { + try { + fieldValue = resources.getResourceTypeName(id) + '/' + + resources.getResourceEntryName(id); + } catch (Resources.NotFoundException e) { + fieldValue = "id/0x" + Integer.toHexString(id); + } + } else { + fieldValue = "NO_ID"; + } + return fieldValue; + } + + private static void writeValue(BufferedWriter out, Object value) throws IOException { + if (value != null) { + String output = value.toString().replace("\n", "\\n"); + out.write(String.valueOf(output.length())); + out.write(","); + out.write(output); + } else { + out.write("4,null"); } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 0f15b17..220869c 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -54,7 +54,7 @@ import android.view.animation.Animation; * window manager is a very low-level system service, there are few other * system services you can call with this lock held. It is explicitly okay to * make calls into the package manager and power manager; it is explicitly not - * okay to make calls into the activity manager. Note that + * okay to make calls into the activity manager or most other services. Note that * {@link android.content.Context#checkPermission(String, int, int)} and * variations require calling into the activity manager. * <dt> Li <dd> Called with the input thread lock held. This lock can be @@ -748,7 +748,7 @@ public interface WindowManagerPolicy { * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}), return a surface * rotation. */ - public int rotationForOrientation(int orientation, int lastRotation, + public int rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled); /** @@ -781,16 +781,16 @@ public interface WindowManagerPolicy { */ public boolean isCheekPressedAgainstScreen(MotionEvent ev); - public void setCurrentOrientation(int newOrientation); + public void setCurrentOrientationLw(int newOrientation); /** * Call from application to perform haptic feedback on its window. */ - public boolean performHapticFeedback(WindowState win, int effectId, boolean always); + public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always); /** * Called when we have stopped keeping the screen on because a window * requesting this is no longer visible. */ - public void screenOnStopped(); + public void screenOnStoppedLw(); } diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 4e98591..b4c5b72 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -174,6 +174,14 @@ public final class InputMethodInfo implements Parcelable { } /** + * Return the raw information about the Service implementing this + * input method. Do not modify the returned object. + */ + public ServiceInfo getServiceInfo() { + return mService.serviceInfo; + } + + /** * Return the component of the service that implements this input * method. */ diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 7f2142e..4de9eef 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -921,6 +921,7 @@ public final class InputMethodManager { startInputInner(); } }); + return; } // Okay we are now ready to call into the served view and have it |