package com.example.android; import static com.example.android.recyclerview.RecyclerMainActivity.TAG; import android.annotation.SuppressLint; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; public class Chaser { private final static Chaser thisInstance = new Chaser(); private static final String TAG = "##"; private static final HashMap names; static { names = new HashMap<>(); } public static Chaser getInstance() { return thisInstance; } public static void addName(View view, String name) { names.put(view, name); } public static String getName(View view) { String s = names.get(view); if (s != null) { return s; } return String.format("<<%s>>", view.getClass().getSimpleName()); } public static void clearNames() { names.clear(); } public static String mmss(long msec) { return Chaser.mmss((int)(msec/1000)); } public static String mmss(int sec) { sec %= 3600; return String.format("%02d:%02d", sec/60, sec%60); } public static void wait(int sec, String message) { getInstance().printMethodsOnInstance(0, message); try { Thread.sleep(1000L * sec); } catch (InterruptedException e) { e.printStackTrace(); } } public static void wait(int sec) { getInstance().printMethodsOnInstance(0, ""); try { Thread.sleep(1000L * sec); } catch (InterruptedException e) { e.printStackTrace(); } } public static void method() { getInstance().printMethodsOnInstance(0, ""); } public static void method(int depth) { getInstance().printMethodsOnInstance(depth, ""); } public static void method(String message) { getInstance().printMethodsOnInstance(0, message); } public static void method(int depth, String message) { getInstance().printMethodsOnInstance(depth, message); } public static void method(KeyEvent event, String message) { getInstance().printMethodsOnInstance(0, " KeyCode:" + getKeyCodeName(event.getKeyCode()) + " Action:" + getEventActionName(event.getAction()) + message); } public static void method(View v, KeyEvent event, String message) { getInstance().printMethodsOnInstance(0, getName(v) + " " + getKeyCodeName(event.getKeyCode()) + " Action:" + getEventActionName(event.getAction()) + message); } public static void method(int keyCode, KeyEvent event) { getInstance().printMethodsOnInstance(0, " KeyCode:" + getKeyCodeName(keyCode) + " Action:" + getEventActionName(event.getAction()) ); } public static void method(View v, int keyCode, KeyEvent event) { getInstance().printMethodsOnInstance(0, getName(v) + " KeyCode:" + getKeyCodeName(keyCode) + " Action:" + getEventActionName(event.getAction()) ); } public static void method(int depth, int keyCode, KeyEvent event) { getInstance().printMethodsOnInstance(depth, " KeyCode:" + getKeyCodeName(keyCode) + " Action:" + getEventActionName(event.getAction()) ); } public static void method(View v, int depth, int keyCode, KeyEvent event) { getInstance().printMethodsOnInstance(depth, getName(v) + " KeyCode:" + getKeyCodeName(keyCode) + " Action:" + getEventActionName(event.getAction()) ); } public static void method(int depth, KeyEvent event, String message) { getInstance().printMethodsOnInstance(depth, "KeyCode:" + getKeyCodeName(event.getKeyCode()) + " Action:" + getEventActionName(event.getAction()) + message); } public static void method(MotionEvent event, String message) { getInstance().printMethodsOnInstance(0, "Action:" + getEventActionName(event.getAction()) + message); } public static void method(int depth, MotionEvent event, String message) { getInstance().printMethodsOnInstance(depth, "Action:" + getEventActionName(event.getAction()) + message); } private void printMethodsOnInstance(int depth, String message) { final int base = 4; String class_Method_Line = getClass_Method_Line(Thread.currentThread().getStackTrace()[base].toString()); System.out.println("### " + class_Method_Line + " " + message); StackTraceElement[] elements = Thread.currentThread().getStackTrace(); if (elements.length < base + depth) { depth = elements.length - base; } for (int i = 0; i < depth; i++) { System.out.println("## " + i + ":" + getClass_Method_Line(elements[base + i].toString())); } } public String getClass_Method_Line(String traceElement) { int sourceNameHead = traceElement.indexOf("(") + 1; int methodHead = -1; for (int i = sourceNameHead - 2; i > 0; i--) { String s = traceElement.substring(i, i + 1); if (s.equals(".") || s.equals(":") || s.equals(" ")) { methodHead = i + 1; break; } } if (methodHead < 0) { return traceElement.substring(sourceNameHead); } int classHead = -1; for (int i = methodHead - 2; i > 0; i--) { String s = traceElement.substring(i, i + 1); if (s.equals(".") || s.equals(":") || s.equals(" ")) { classHead = i + 1; break; } } if (classHead < 0) { return traceElement.substring(methodHead); } return traceElement.substring(classHead); } public String getMethodName(String traceElement) { int kakko = traceElement.indexOf("("); int methodHead = 0; for (int i = kakko - 1; i > 0; i--) { if (traceElement.charAt(i) == '.') { methodHead = i + 1; break; } } String methodName = traceElement.substring(methodHead, kakko); int classHead = 0; for (int i = methodHead - 2; i > 0; i--) { if (traceElement.charAt(i) == '.') { classHead = i + 1; break; } } String className = traceElement.substring(classHead, methodHead - 1); return className + "#" + methodName; } private static String getKeyCodeName(int keyCode) { { switch (keyCode) { case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: return "MEDIA_PLAY_PAUSE"; case KeyEvent.KEYCODE_DPAD_RIGHT: return "DPAD_RIGHT"; case KeyEvent.KEYCODE_DPAD_LEFT: return "DPAD_LEFT"; case KeyEvent.KEYCODE_DPAD_DOWN: return "DPAD_DOWN"; case KeyEvent.KEYCODE_DPAD_UP: return "DPAD_UP"; case KeyEvent.KEYCODE_DPAD_CENTER: return "DPAD_CENTER"; case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: return "MEDIA_FAST_FORWARD"; case KeyEvent.KEYCODE_MEDIA_REWIND: return "MEDIA_REWIND"; case KeyEvent.KEYCODE_BACK: return "BACK"; default: } return "UNKNOWN:" + keyCode; } } private static String getEventActionName(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "DOWN"; case MotionEvent.ACTION_UP: return "UP"; case MotionEvent.ACTION_MOVE: return "MOVE"; case MotionEvent.ACTION_CANCEL: return "CANCEL"; } return "UNKNOWN:" + action; } static public String getViewVisibility(View view) { if (view == null) { return "[null]"; } switch (view.getVisibility()) { case View.VISIBLE: return "Visible"; case View.INVISIBLE: return "Invisible"; case View.GONE: return "Gone"; default: return "Unknown"; } } static public String getVis(View view) { if (view == null) { return "-"; } switch (view.getVisibility()) { case View.VISIBLE: return "o"; case View.INVISIBLE: return "x"; case View.GONE: return "/"; default: return "?"; } } static public void printViewMetric(View view) { Log.d(TAG, getViewMetric(view)); } static public String getViewMetric(View view) { if (view == null) { return "## [null]"; } int[] inWindow = new int[2]; view.getLocationInWindow(inWindow); return String.format(Locale.JAPAN, "## H:%d W:%d (%d, %d)-(%d, %d) %s", view.getHeight(), view.getWidth(), inWindow[0], inWindow[1], inWindow[0] + view.getWidth(), inWindow[1] + view.getHeight(), getViewVisibility(view)) + String.format(Locale.JAPAN, "## %d %d %d %d", inWindow[0], view.getWidth(), inWindow[1], view.getHeight()); } @SuppressLint("DefaultLocale") public static void viewTree(ViewGroup viewGroup, int levelLimit) { viewTree(viewGroup, "", levelLimit); } @SuppressLint("DefaultLocale") public static void viewTree(ViewGroup viewGroup, String message, int levelLimit) { ArrayList list = new ArrayList<>(); viewTree(list, viewGroup, 0, levelLimit); generateTreeIndent1(list, levelLimit); String format = "##%s(%5d,%5d) H=%5d, W=%5d %s%s %s"; for (int i = 0; i < list.size(); i++) { final ViewTreeElement e = list.get(i); while (e.indent.length() < levelLimit) { e.indent += "."; } Log.d(TAG, String.format(Locale.JAPAN, format,e.visibility, e.x, e.y, e.height, e.width, e.indent, e.name, message)); } } private static void generateTreeIndent1(ArrayList list, int levelLimit) { for (int i = 0; i < list.size(); i++) { final ViewTreeElement e = list.get(i); e.indent = ""; int level = 0; while (level++ < e.level) { e.indent += "+"; } while (level++ < levelLimit) { e.indent += "."; } } } private static void generateTreeIndent(ArrayList list, int levelLimit) { int prevLevel = -10; int currentLevel = list.get(0).level; int nextLevel = list.get(1).level; list.get(0).prevLevel = -10; list.get(0).level = currentLevel; list.get(0).nextLevel = nextLevel; for (int next = 2; next < list.size(); next++) { prevLevel = currentLevel; currentLevel = nextLevel; nextLevel = list.get(next).level; list.get(next - 1).prevLevel = prevLevel; list.get(next - 1).level = currentLevel; list.get(next - 1).nextLevel = nextLevel; } int last = list.size() - 1; list.get(last).prevLevel = currentLevel; list.get(last).level = nextLevel; list.get(last).nextLevel = 0; String prevIndent = ""; for (int level = 0; level < levelLimit; level++) { prevIndent += " "; } //level 0 String prevIndentChar = ""; for (int i = 0; i < list.size(); i++) { String indentChar = " "; for (int j = i + 1; j < list.size(); j++) { if (list.get(j).level == 0) { list.get(j).indent = ""; } } } for (int level = 1; level < levelLimit; level++) { for (int i = 0; i < list.size(); i++) { final ViewTreeElement e = list.get(i); Character indentChar = ' '; if (e.level == e.prevLevel + 1) { indentChar = prevIndentChar.charAt(level); } if (e.level == e.prevLevel) { indentChar = prevIndentChar.charAt(level); } if (e.level < e.prevLevel) { if (level < e.level) { indentChar = prevIndentChar.charAt(level); } else if (level == e.level) { indentChar = '+'; } else if (level < e.level) { indentChar = '.'; } } } } // // final ViewTreeElement e = list.get(i); // switch (e.level) { // case 0: // e.indent = ""; // break; // case 1: // e.indent = "+"; // break; // default: // e.indent = "|"; // for (int depth = 1; depth < e.level; depth++) { // String indentChar = " "; // for (int j = i + 1; j < list.size(); j++) { // if (list.get(j).level < depth) { // break; // } else if (list.get(j).level == depth) { // indentChar = "|"; // break; // } // } // e.indent += indentChar; // } // break; // } // e.indent += "+"; // } } public static void viewTree(ArrayList list, ViewGroup viewGroup, int level, int levelLimit) { viewTree(list, viewGroup, level, levelLimit, true); } public static void viewTree(ArrayList list, ViewGroup viewGroup, int level, int levelLimit, boolean recursive) { if (level > levelLimit) { return; } for (int i = 0; i < viewGroup.getChildCount(); i++) { View view = viewGroup.getChildAt(i); int[] inWindow = new int[2]; view.getLocationInWindow(inWindow); String name = getName(view); if (name.charAt(0) == '+') { recursive = false; } list.add(new ViewTreeElement(level, name, getVis(view), inWindow[0], inWindow[1], view.getWidth(), view.getHeight())); if (recursive && (view instanceof ViewGroup)) { viewTree(list, (ViewGroup) view, level + 1, levelLimit, true); } } } static class ViewTreeElement { public int level; public int nextLevel; public int prevLevel; public String name; public String indent; public String visibility; public int x; public int y; public int width; public int height; public ViewTreeElement(int level, String name, String visibility, int x, int y, int width, int height) { this.level = level; this.name = name; this.visibility = visibility; this.x = x; this.y = y; this.width = width; this.height = height; } } }