am 0ea30200: am 676c97eb: Merge "Remove voodoo magic."
* commit '0ea30200b4031815f81887ccacc605c23c7655b2': Remove voodoo magic.main
commit
fb49fb9e7a
|
@ -162,45 +162,22 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> {
|
||||||
// on the same thread that the tests are running on to mimic the actual environment as
|
// on the same thread that the tests are running on to mimic the actual environment as
|
||||||
// closely as possible.
|
// closely as possible.
|
||||||
// Now, Looper#loop() never exits in normal operation unless the Looper#quit() method
|
// Now, Looper#loop() never exits in normal operation unless the Looper#quit() method
|
||||||
// is called, so we need to do that at the right time so that #loop() returns at some
|
// is called, which has a lot of bad side effects. We can however just throw an exception
|
||||||
// point and we don't end up in an infinite loop.
|
// in the runnable which will unwind the stack and allow us to exit.
|
||||||
// After we quit, the looper is still technically ready to process more messages but
|
private final class InterruptRunMessagesException extends RuntimeException {
|
||||||
// the handler will refuse to enqueue any because #quit() has been called and it
|
// Empty class
|
||||||
// explicitly tests for it on message enqueuing, so we'll have to reset it so that
|
}
|
||||||
// it lets us continue normal operation.
|
|
||||||
protected void runMessages() {
|
protected void runMessages() {
|
||||||
// Here begins deep magic.
|
|
||||||
final Looper looper = mLatinIME.mHandler.getLooper();
|
|
||||||
mLatinIME.mHandler.post(new Runnable() {
|
mLatinIME.mHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
looper.quit();
|
throw new InterruptRunMessagesException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// The only way to get out of Looper#loop() is to call #quit() on it (or on its queue).
|
|
||||||
// Once #quit() is called remaining messages are not processed, which is why we post
|
|
||||||
// a message that calls it instead of calling it directly.
|
|
||||||
Looper.loop();
|
|
||||||
|
|
||||||
// Once #quit() has been called, the looper is not functional any more (it used to be,
|
|
||||||
// but now it SIGSEGV's if it's used again).
|
|
||||||
// It won't accept creating a new looper for this thread and switching to it...
|
|
||||||
// ...unless we can trick it into throwing out the old looper and believing it hasn't
|
|
||||||
// been initialized before.
|
|
||||||
MessageQueue queue = Looper.myQueue();
|
|
||||||
try {
|
try {
|
||||||
// However there is no way of doing it externally, and the static ThreadLocal
|
Looper.loop();
|
||||||
// field into which it's stored is private.
|
} catch (InterruptRunMessagesException e) {
|
||||||
// So... get out the big guns.
|
// Resume normal operation
|
||||||
java.lang.reflect.Field f = Looper.class.getDeclaredField("sThreadLocal");
|
|
||||||
f.setAccessible(true); // private lolwut
|
|
||||||
final ThreadLocal<Looper> a = (ThreadLocal<Looper>) f.get(looper);
|
|
||||||
a.set(null);
|
|
||||||
looper.prepare();
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue