package org.acra.collector; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.acra.ACRA; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; import android.util.SparseArray; import android.view.Display; import android.view.Surface; import android.view.WindowManager; import static org.acra.ACRA.LOG_TAG; final class DisplayManagerCollector { final static SparseArray<String> mFlagsNames = new SparseArray<String>(); final static SparseArray<String> mDensities = new SparseArray<String>(); public static String collectDisplays(Context ctx) { Display[] displays = null; final StringBuilder result = new StringBuilder(); if (Compatibility.getAPILevel() < Compatibility.VERSION_CODES.JELLY_BEAN_MR1) { // Before Android 4.2, there was a single display available from the // window manager final WindowManager windowManager = (WindowManager) ctx .getSystemService(Context.WINDOW_SERVICE); displays = new Display[1]; displays[0] = windowManager.getDefaultDisplay(); } else { // Since Android 4.2, we can fetch multiple displays with the // DisplayManager. try { Object displayManager = ctx.getSystemService((String) (ctx.getClass().getField("DISPLAY_SERVICE") .get(null))); Method getDisplays = displayManager.getClass().getMethod("getDisplays"); displays = (Display[]) getDisplays.invoke(displayManager); } catch (IllegalArgumentException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } catch (SecurityException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } catch (IllegalAccessException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } catch (NoSuchFieldException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } catch (NoSuchMethodException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } catch (InvocationTargetException e) { ACRA.log.w(LOG_TAG, "Error while collecting DisplayManager data: ", e); } } for (Display display : displays) { result.append(collectDisplayData(display)); } return result.toString(); } private static Object collectDisplayData(Display display) { final DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); final StringBuilder result = new StringBuilder(); result.append(collectCurrentSizeRange(display)); result.append(collectFlags(display)); result.append(display.getDisplayId()).append(".height=").append(display.getHeight()).append('\n'); result.append(collectMetrics(display, "getMetrics")); result.append(collectName(display)); result.append(display.getDisplayId()).append(".orientation=").append(display.getOrientation()).append('\n'); result.append(display.getDisplayId()).append(".pixelFormat=").append(display.getPixelFormat()).append('\n'); result.append(collectMetrics(display, "getRealMetrics")); result.append(collectSize(display, "getRealSize")); result.append(collectRectSize(display)); result.append(display.getDisplayId()).append(".refreshRate=").append(display.getRefreshRate()).append('\n'); result.append(collectRotation(display)); result.append(collectSize(display, "getSize")); result.append(display.getDisplayId()).append(".width=").append(display.getWidth()).append('\n'); result.append(collectIsValid(display)); return result.toString(); } private static Object collectIsValid(Display display) { StringBuilder result = new StringBuilder(); try { Method isValid = display.getClass().getMethod("isValid"); Boolean value = (Boolean) isValid.invoke(display); result.append(display.getDisplayId()).append(".isValid=").append(value).append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static Object collectRotation(Display display) { StringBuilder result = new StringBuilder(); try { Method getRotation = display.getClass().getMethod("getRotation"); int rotation = (Integer) getRotation.invoke(display); result.append(display.getDisplayId()).append(".rotation="); switch (rotation) { case Surface.ROTATION_0: result.append("ROTATION_0"); break; case Surface.ROTATION_90: result.append("ROTATION_90"); break; case Surface.ROTATION_180: result.append("ROTATION_180"); break; case Surface.ROTATION_270: result.append("ROTATION_270"); break; default: result.append(rotation); break; } result.append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static Object collectRectSize(Display display) { StringBuilder result = new StringBuilder(); try { Method getRectSize = display.getClass().getMethod("getRectSize", Rect.class); Rect size = new Rect(); getRectSize.invoke(display, size); result.append(display.getDisplayId()).append(".rectSize=[").append(size.top).append(',').append(size.left) .append(',').append(size.width()).append(',').append(size.height()).append(']').append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static Object collectSize(Display display, String methodName) { StringBuilder result = new StringBuilder(); try { Method getRealSize = display.getClass().getMethod(methodName, Point.class); Point size = new Point(); getRealSize.invoke(display, size); result.append(display.getDisplayId()).append('.').append(methodName).append("=[").append(size.x) .append(',').append(size.y).append(']').append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static String collectCurrentSizeRange(Display display) { StringBuilder result = new StringBuilder(); try { Method getCurrentSizeRange = display.getClass().getMethod("getCurrentSizeRange", Point.class, Point.class); Point smallest = new Point(), largest = new Point(); getCurrentSizeRange.invoke(display, smallest, largest); result.append(display.getDisplayId()).append(".currentSizeRange.smallest=[").append(smallest.x).append(',') .append(smallest.y).append(']').append('\n'); result.append(display.getDisplayId()).append(".currentSizeRange.largest=[").append(largest.x).append(',') .append(largest.y).append(']').append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static String collectFlags(Display display) { StringBuilder result = new StringBuilder(); try { Method getFlags = display.getClass().getMethod("getFlags"); int flags = (Integer) getFlags.invoke(display); for (Field field : display.getClass().getFields()) { if (field.getName().startsWith("FLAG_")) { mFlagsNames.put(field.getInt(null), field.getName()); } } result.append(display.getDisplayId()).append(".flags=").append(activeFlags(mFlagsNames, flags)) .append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static String collectName(Display display) { StringBuilder result = new StringBuilder(); try { Method getName = display.getClass().getMethod("getName"); String name = (String) getName.invoke(display); result.append(display.getDisplayId()).append(".name=").append(name).append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return result.toString(); } private static Object collectMetrics(Display display, String methodName) { StringBuilder result = new StringBuilder(); try { Method getMetrics = display.getClass().getMethod(methodName); DisplayMetrics metrics = (DisplayMetrics) getMetrics.invoke(display); for (Field field : DisplayMetrics.class.getFields()) { if (field.getType().equals(Integer.class) && field.getName().startsWith("DENSITY_") && !field.getName().equals("DENSITY_DEFAULT")) { mDensities.put(field.getInt(null), field.getName()); } } result.append(display.getDisplayId()).append('.').append(methodName).append(".density=") .append(metrics.density).append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append(".densityDpi=") .append(metrics.getClass().getField("densityDpi")).append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append("scaledDensity=x") .append(metrics.scaledDensity).append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append(".widthPixels=") .append(metrics.widthPixels).append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append(".heightPixels=") .append(metrics.heightPixels).append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append(".xdpi=").append(metrics.xdpi) .append('\n'); result.append(display.getDisplayId()).append('.').append(methodName).append(".ydpi=").append(metrics.ydpi) .append('\n'); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } catch (NoSuchFieldException e) { } return result.toString(); } /** * Some fields contain multiple value types which can be isolated by * applying a bitmask. That method returns the concatenation of active * values. * * @param valueNames * The array containing the different values and names for this * field. Must contain mask values too. * @param bitfield * The bitfield to inspect. * @return The names of the different values contained in the bitfield, * separated by '+'. */ private static String activeFlags(SparseArray<String> valueNames, int bitfield) { final StringBuilder result = new StringBuilder(); // Look for masks, apply it an retrieve the masked value for (int i = 0; i < valueNames.size(); i++) { final int maskValue = valueNames.keyAt(i); final int value = bitfield & maskValue; if (value > 0) { if (result.length() > 0) { result.append('+'); } result.append(valueNames.get(value)); } } return result.toString(); } }