public void waitForUiThread(Handler icHandler) {
   if (DEBUG) {
     ThreadUtils.assertOnThread(icHandler.getLooper().getThread(), AssertBehavior.THROW);
     Log.d(
         LOGTAG,
         "waitForUiThread() blocking on thread " + icHandler.getLooper().getThread().getName());
   }
   try {
     Runnable runnable = null;
     do {
       runnable = mIcRunnableSync.take();
       runnable.run();
     } while (runnable != mIcSignalRunnable);
   } catch (InterruptedException e) {
   }
 }
 public Editable getEditableForUiThread(
     final Handler uiHandler, final GoannaEditableClient client) {
   if (DEBUG) {
     ThreadUtils.assertOnThread(uiHandler.getLooper().getThread(), AssertBehavior.THROW);
   }
   final Handler icHandler = client.getInputConnectionHandler();
   if (icHandler.getLooper() == uiHandler.getLooper()) {
     // IC thread is UI thread; safe to use Editable directly
     return client.getEditable();
   }
   // IC thread is not UI thread; we need to return a proxy Editable in order
   // to safely use the Editable from the UI thread
   if (mUiEditable != null) {
     return mUiEditable;
   }
   final InvocationHandler invokeEditable =
       new InvocationHandler() {
         @Override
         public Object invoke(final Object proxy, final Method method, final Object[] args)
             throws Throwable {
           if (DEBUG) {
             ThreadUtils.assertOnThread(uiHandler.getLooper().getThread(), AssertBehavior.THROW);
             Log.d(LOGTAG, "UiEditable." + method.getName() + "() blocking");
           }
           synchronized (icHandler) {
             // Now we are on UI thread
             mUiEditableReturn = null;
             mUiEditableException = null;
             // Post a Runnable that calls the real Editable and saves any
             // result/exception. Then wait on the Runnable to finish
             runOnIcThread(
                 icHandler,
                 new Runnable() {
                   @Override
                   public void run() {
                     synchronized (icHandler) {
                       try {
                         mUiEditableReturn = method.invoke(client.getEditable(), args);
                       } catch (Exception e) {
                         mUiEditableException = e;
                       }
                       if (DEBUG) {
                         Log.d(LOGTAG, "UiEditable." + method.getName() + "() returning");
                       }
                       icHandler.notify();
                     }
                   }
                 });
             // let InterruptedException propagate
             icHandler.wait();
             if (mUiEditableException != null) {
               throw mUiEditableException;
             }
             return mUiEditableReturn;
           }
         }
       };
   mUiEditable =
       (Editable)
           Proxy.newProxyInstance(
               Editable.class.getClassLoader(), new Class<?>[] {Editable.class}, invokeEditable);
   return mUiEditable;
 }