Bug 805162 - i. Refactor DebugGeckoInputConnection to be smaller by using reflection; r=cpeterson

This commit is contained in:
Jim Chen 2012-10-31 17:35:32 -04:00
parent eb12abdc9f
commit 2e2ea9bad7

View File

@ -26,6 +26,9 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Timer;
import java.util.TimerTask;
@ -553,260 +556,77 @@ class GeckoInputConnection
});
}
}
}
private static final class DebugGeckoInputConnection extends GeckoInputConnection {
public DebugGeckoInputConnection(View targetView) {
super(targetView);
GeckoApp.assertOnUiThread();
final class DebugGeckoInputConnection
extends GeckoInputConnection
implements InvocationHandler {
private InputConnection mProxy;
private DebugGeckoInputConnection(View targetView,
GeckoEditableClient editable) {
super(targetView, editable);
}
@Override
public boolean beginBatchEdit() {
Log.d(LOGTAG, "IME: beginBatchEdit: mBatchEditCount " + mBatchEditCount
+ " -> " + (mBatchEditCount+1));
GeckoApp.assertOnUiThread();
return super.beginBatchEdit();
public static InputConnectionHandler create(View targetView,
GeckoEditableClient editable) {
final Class[] PROXY_INTERFACES = { InputConnection.class,
InputConnectionHandler.class,
GeckoEditableListener.class };
DebugGeckoInputConnection dgic =
new DebugGeckoInputConnection(targetView, editable);
dgic.mProxy = (InputConnection)Proxy.newProxyInstance(
GeckoInputConnection.class.getClassLoader(),
PROXY_INTERFACES, dgic);
editable.setListener((GeckoEditableListener)dgic.mProxy);
return (InputConnectionHandler)dgic.mProxy;
}
@Override
public boolean endBatchEdit() {
Log.d(LOGTAG, "IME: endBatchEdit: mBatchEditCount " + mBatchEditCount
+ " -> " + (mBatchEditCount-1));
GeckoApp.assertOnUiThread();
if (mBatchEditCount <= 0) {
throw new IllegalStateException("Expected positive mBatchEditCount, but got "
+ mBatchEditCount);
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()) {
Class cls = obj.getClass();
sb.append(cls.getComponentType().getSimpleName()).append("[")
.append(java.lang.reflect.Array.getLength(obj)).append("]");
} else {
sb.append(obj.toString());
}
return super.endBatchEdit();
return sb;
}
@Override
public boolean commitCompletion(CompletionInfo text) {
Log.d(LOGTAG, "IME: commitCompletion");
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
GeckoApp.assertOnUiThread();
return super.commitCompletion(text);
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: commitText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.commitText(text, newCursorPosition);
}
@Override
public boolean deleteSurroundingText(int leftLength, int rightLength) {
Log.d(LOGTAG, "IME: deleteSurroundingText(leftLen=" + leftLength + ", rightLen="
+ rightLength + ")");
GeckoApp.assertOnUiThread();
return super.deleteSurroundingText(leftLength, rightLength);
}
@Override
public boolean finishComposingText() {
Log.d(LOGTAG, "IME: finishComposingText");
// finishComposingText will post itself to the ui thread,
// no need to assert it.
return super.finishComposingText();
}
@Override
public Editable getEditable() {
Editable editable = super.getEditable();
Log.d(LOGTAG, "IME: getEditable -> " + prettyPrintString(editable));
// FIXME: Uncomment assert after bug 780543 is fixed. //GeckoApp.assertOnUiThread();
return editable;
}
@Override
public boolean performContextMenuAction(int id) {
Log.d(LOGTAG, "IME: performContextMenuAction");
GeckoApp.assertOnUiThread();
return super.performContextMenuAction(id);
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
Log.d(LOGTAG, "IME: getExtractedText");
GeckoApp.assertOnUiThread();
ExtractedText extract = super.getExtractedText(req, flags);
if (extract != null)
Log.d(LOGTAG, String.format(
". . . getExtractedText: extract.text=\"%s\", selStart=%d, selEnd=%d",
extract.text, extract.selectionStart, extract.selectionEnd));
return extract;
}
@Override
public CharSequence getTextAfterCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextAfterCursor(length=" + length + ", flags=" + flags + ")");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextAfterCursor(length, flags);
Log.d(LOGTAG, ". . . getTextAfterCursor returns \"" + s + "\"");
return s;
}
@Override
public CharSequence getTextBeforeCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextBeforeCursor");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextBeforeCursor(length, flags);
Log.d(LOGTAG, ". . . getTextBeforeCursor returns \"" + s + "\"");
return s;
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: setComposingText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.setComposingText(text, newCursorPosition);
}
@Override
public boolean setComposingRegion(int start, int end) {
Log.d(LOGTAG, "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setComposingRegion(start, end);
}
@Override
public boolean setSelection(int start, int end) {
Log.d(LOGTAG, "IME: setSelection(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setSelection(start, end);
}
@Override
public String getComposingText() {
Log.d(LOGTAG, "IME: getComposingText");
GeckoApp.assertOnUiThread();
String s = super.getComposingText();
Log.d(LOGTAG, ". . . getComposingText: Composing text = \"" + s + "\"");
return s;
}
@Override
public boolean onKeyDel() {
Log.d(LOGTAG, "IME: onKeyDel");
GeckoApp.assertOnUiThread();
return super.onKeyDel();
}
@Override
protected void notifyTextChange(String text, int start, int oldEnd, int newEnd) {
// notifyTextChange() call is posted to UI thread from notifyIMEChange().
GeckoApp.assertOnUiThread();
String msg = String.format("IME: >notifyTextChange(%s, start=%d, oldEnd=%d, newEnd=%d)",
prettyPrintString(text), start, oldEnd, newEnd);
Log.d(LOGTAG, msg);
if (start < 0 || oldEnd < start || newEnd < start || newEnd > text.length()) {
throw new IllegalArgumentException("BUG! " + msg);
Object ret = method.invoke(this, args);
if (ret == this) {
ret = mProxy;
}
super.notifyTextChange(text, start, oldEnd, newEnd);
}
@Override
protected void notifySelectionChange(int start, int end) {
// notifySelectionChange() call is posted to UI thread from notifyIMEChange().
// FIXME: Uncomment assert after bug 780543 is fixed.
//GeckoApp.assertOnUiThread();
Log.d(LOGTAG, String.format("IME: >notifySelectionChange(start=%d, end=%d)", start, end));
super.notifySelectionChange(start, end);
}
@Override
protected void resetCompositionState() {
Log.d(LOGTAG, "IME: resetCompositionState");
GeckoApp.assertOnUiThread();
if (hasCompositionString()) {
Log.d(LOGTAG, "resetCompositionState() is abandoning an active composition string");
StringBuilder log = new StringBuilder(method.getName());
log.append("(");
for (Object arg : args) {
debugAppend(log, arg).append(", ");
}
super.resetCompositionState();
}
if (args.length > 0) {
log.setLength(log.length() - 2);
}
if (method.getReturnType().equals(Void.TYPE)) {
log.append(")");
} else {
debugAppend(log.append(") = "), ret);
}
Log.d(LOGTAG, log.toString());
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(LOGTAG, String.format("IME: onTextChanged(\"%s\" start=%d, before=%d, count=%d)",
s, start, before, count));
GeckoApp.assertOnUiThread();
super.onTextChanged(s, start, before, count);
}
@Override
public void afterTextChanged(Editable s) {
Log.d(LOGTAG, "IME: afterTextChanged(\"" + s + "\")");
GeckoApp.assertOnUiThread();
super.afterTextChanged(s);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d(LOGTAG, String.format("IME: beforeTextChanged(\"%s\", start=%d, count=%d, after=%d)",
s, start, count, after));
GeckoApp.assertOnUiThread();
super.beforeTextChanged(s, start, count, after);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
Log.d(LOGTAG, "IME: onCreateInputConnection called");
GeckoApp.assertOnUiThread();
return super.onCreateInputConnection(outAttrs);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyPreIme(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyDown(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyUp(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyMultiple(keyCode=" + keyCode + ", repeatCount=" + repeatCount
+ ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyMultiple(keyCode, repeatCount, event);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyLongPress(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyLongPress(keyCode, event);
}
@Override
public void notifyIME(int type, int state) {
Log.d(LOGTAG, "IME: >notifyIME(type=" + type + ", state=" + state + ")");
GeckoApp.assertOnGeckoThread();
super.notifyIME(type, state);
}
@Override
public void notifyIMEEnabled(int state, String typeHint, String modeHint, String actionHint) {
Log.d(LOGTAG, "IME: >notifyIMEEnabled(state=" + state + ", typeHint=\"" + typeHint
+ "\", modeHint=\"" + modeHint + "\", actionHint=\""
+ actionHint + "\"");
GeckoApp.assertOnGeckoThread();
if (state < IME_STATE_DISABLED || state > IME_STATE_PLUGIN)
throw new IllegalArgumentException("Unexpected IMEState=" + state);
super.notifyIMEEnabled(state, typeHint, modeHint, actionHint);
return ret;
}
}
}