Bug 838177 - Add more debugging output to GeckoEditable and GeckoInputConnection; r=cpeterson

This commit is contained in:
Jim Chen 2013-02-18 13:57:43 -05:00
parent cd8dd057b0
commit 3cb8a6523e
2 changed files with 93 additions and 33 deletions

View File

@ -23,6 +23,7 @@ import android.text.TextUtils;
import android.text.style.CharacterStyle;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -191,6 +192,8 @@ final class GeckoEditable
void offer(Action action) {
if (DEBUG) {
assertOnIcThread();
Log.d(LOGTAG, "offer: Action(" +
getConstantName(Action.class, "TYPE_", action.mType) + ")");
}
/* Events don't need update because they generate text/selection
notifications which will do the updating for us */
@ -261,8 +264,14 @@ final class GeckoEditable
assertOnIcThread();
}
if (mFocused && !mActions.isEmpty()) {
if (DEBUG) {
Log.d(LOGTAG, "syncWithGecko blocking on thread " +
Thread.currentThread().getName());
}
mActionsActive.acquireUninterruptibly();
mActionsActive.release();
} else if (DEBUG && !mFocused) {
Log.d(LOGTAG, "skipped syncWithGecko (no focus)");
}
}
@ -445,7 +454,8 @@ final class GeckoEditable
rangeStart = rangeEnd;
if (DEBUG) {
Log.d(LOGTAG, " added " + rangeType + " : " + rangeStyles +
Log.d(LOGTAG, " added " + rangeType +
" : " + Integer.toHexString(rangeStyles) +
" : " + Integer.toHexString(rangeForeColor) +
" : " + Integer.toHexString(rangeBackColor));
}
@ -459,6 +469,9 @@ final class GeckoEditable
@Override
public void sendEvent(final GeckoEvent event) {
if (DEBUG) {
Log.d(LOGTAG, "sendEvent(" + event + ")");
}
if (!onIcThread()) {
// Events may get dispatched to the main thread;
// reroute to our IC thread instead
@ -585,6 +598,10 @@ final class GeckoEditable
}
final Action action = mActionQueue.peek();
if (DEBUG) {
Log.d(LOGTAG, "reply: Action(" +
getConstantName(Action.class, "TYPE_", action.mType) + ")");
}
switch (action.mType) {
case Action.TYPE_SET_SELECTION:
final int len = mText.length();
@ -629,6 +646,12 @@ final class GeckoEditable
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
// NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply()
if (type != NOTIFY_IME_REPLY_EVENT) {
Log.d(LOGTAG, "notifyIME(" +
getConstantName(GeckoEditableListener.class, "NOTIFY_IME_", type) +
", " + state + ")");
}
}
if (type == NOTIFY_IME_REPLY_EVENT) {
try {
@ -636,6 +659,8 @@ final class GeckoEditable
// When mFocused is false, the reply is for a stale action,
// and we should not do anything
geckoActionReply();
} else if (DEBUG) {
Log.d(LOGTAG, "discarding stale reply");
}
} finally {
// Ensure action is always removed from queue
@ -669,6 +694,11 @@ final class GeckoEditable
final String modeHint, final String actionHint) {
// Because we want to be able to bind GeckoEditable to the newest LayerView instance,
// this can be called from the Java IC thread in addition to the Gecko thread.
if (DEBUG) {
Log.d(LOGTAG, "notifyIMEEnabled(" +
getConstantName(GeckoEditableListener.class, "IME_STATE_", state) +
", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")");
}
geckoPostToIc(new Runnable() {
public void run() {
// Make sure there are no other things going on
@ -691,6 +721,7 @@ final class GeckoEditable
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
}
if (start < 0 || start > mText.length() || end < 0 || end > mText.length()) {
throw new IllegalArgumentException("invalid selection notification range");
@ -739,6 +770,8 @@ final class GeckoEditable
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
Log.d(LOGTAG, "onTextChange(\"" + text + "\", " + start + ", " +
unboundedOldEnd + ", " + unboundedNewEnd + ")");
}
if (start < 0 || start > unboundedOldEnd) {
throw new IllegalArgumentException("invalid text notification range");
@ -812,7 +845,20 @@ final class GeckoEditable
// InvocationHandler interface
private static StringBuilder debugAppend(StringBuilder sb, Object obj) {
static String getConstantName(Class<?> cls, String prefix, Object value) {
for (Field fld : cls.getDeclaredFields()) {
try {
if (fld.getName().startsWith(prefix) &&
fld.get(null).equals(value)) {
return fld.getName();
}
} catch (IllegalAccessException e) {
}
}
return String.valueOf(value);
}
static StringBuilder debugAppend(StringBuilder sb, Object obj) {
if (obj == null) {
sb.append("null");
} else if (obj instanceof GeckoEditable) {

View File

@ -63,6 +63,8 @@ class GeckoInputConnection
private void runOnIcThread(Handler icHandler, final Runnable runnable) {
if (DEBUG) {
GeckoApp.assertOnUiThread();
Log.d(LOGTAG, "runOnIcThread() on thread " +
icHandler.getLooper().getThread().getName());
}
Runnable runner = new Runnable() {
@Override public void run() {
@ -91,6 +93,7 @@ class GeckoInputConnection
public void endWaitForUiThread() {
if (DEBUG) {
GeckoApp.assertOnUiThread();
Log.d(LOGTAG, "endWaitForUiThread()");
}
try {
mIcRunnableSync.put(mIcSignalRunnable);
@ -101,6 +104,8 @@ class GeckoInputConnection
public void waitForUiThread(Handler icHandler) {
if (DEBUG) {
GeckoApp.assertOnThread(icHandler.getLooper().getThread());
Log.d(LOGTAG, "waitForUiThread() blocking on thread " +
icHandler.getLooper().getThread().getName());
}
try {
Runnable runnable = null;
@ -132,6 +137,7 @@ class GeckoInputConnection
final Object[] args) throws Throwable {
if (DEBUG) {
GeckoApp.assertOnThread(uiHandler.getLooper().getThread());
Log.d(LOGTAG, "UiEditable." + method.getName() + "() blocking");
}
synchronized (icHandler) {
// Now we are on UI thread
@ -148,6 +154,10 @@ class GeckoInputConnection
} catch (Exception e) {
mUiEditableException = e;
}
if (DEBUG) {
Log.d(LOGTAG, "UiEditable." + method.getName() +
"() returning");
}
icHandler.notify();
}
}
@ -580,6 +590,12 @@ class GeckoInputConnection
| EditorInfo.IME_FLAG_NO_FULLSCREEN;
}
if (DEBUG) {
Log.d(LOGTAG, "mapped IME states to: inputType = " +
Integer.toHexString(outAttrs.inputType) + ", imeOptions = " +
Integer.toHexString(outAttrs.imeOptions));
}
String prevInputMethod = mCurrentInputMethod;
mCurrentInputMethod = InputMethods.getCurrentInputMethod(app);
if (DEBUG) {
@ -838,10 +854,12 @@ final class DebugGeckoInputConnection
implements InvocationHandler {
private InputConnection mProxy;
private StringBuilder mCallLevel;
private DebugGeckoInputConnection(View targetView,
GeckoEditableClient editable) {
super(targetView, editable);
mCallLevel = new StringBuilder();
}
public static GeckoEditableListener create(View targetView,
@ -857,47 +875,43 @@ final class DebugGeckoInputConnection
return (GeckoEditableListener)dgic.mProxy;
}
private static StringBuilder debugAppend(StringBuilder sb, Object obj) {
if (obj == null) {
sb.append("null");
} else if (obj instanceof GeckoEditable) {
sb.append("GeckoEditable");
} else if (Proxy.isProxyClass(obj.getClass())) {
debugAppend(sb, Proxy.getInvocationHandler(obj));
} else if (obj instanceof CharSequence) {
sb.append("\"").append(obj.toString().replace('\n', '\u21b2')).append("\"");
} else if (obj.getClass().isArray()) {
sb.append(obj.getClass().getComponentType().getSimpleName()).append("[")
.append(java.lang.reflect.Array.getLength(obj)).append("]");
} else {
sb.append(obj.toString());
}
return sb;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret = method.invoke(this, args);
if (ret == this) {
ret = mProxy;
}
StringBuilder log = new StringBuilder(method.getName());
log.append("(");
StringBuilder log = new StringBuilder(mCallLevel);
log.append("> ").append(method.getName()).append("(");
for (Object arg : args) {
debugAppend(log, arg).append(", ");
// translate argument values to constant names
if ("notifyIME".equals(method.getName()) && arg == args[0]) {
log.append(GeckoEditable.getConstantName(
GeckoEditableListener.class, "NOTIFY_IME_", arg));
} else if ("notifyIMEEnabled".equals(method.getName()) && arg == args[0]) {
log.append(GeckoEditable.getConstantName(
GeckoEditableListener.class, "IME_STATE_", arg));
} else {
GeckoEditable.debugAppend(log, arg);
}
log.append(", ");
}
if (args.length > 0) {
log.setLength(log.length() - 2);
}
if (method.getReturnType().equals(Void.TYPE)) {
log.append(")");
} else {
debugAppend(log.append(") = "), ret);
}
log.append(")");
Log.d(LOGTAG, log.toString());
mCallLevel.append(' ');
Object ret = method.invoke(this, args);
if (ret == this) {
ret = mProxy;
}
mCallLevel.setLength(Math.max(0, mCallLevel.length() - 1));
log.setLength(mCallLevel.length());
log.append("< ").append(method.getName());
if (!method.getReturnType().equals(Void.TYPE)) {
GeckoEditable.debugAppend(log.append(": "), ret);
}
Log.d(LOGTAG, log.toString());
return ret;
}
}