Dispose handler per-session callbacks

Bug: 148785814
Test: all tests should pass
Change-Id: I53677ba88aa2aa7b242b59ad7c84746f0ceeef5a
diff --git a/bridge/src/android/os/Handler_Delegate.java b/bridge/src/android/os/Handler_Delegate.java
index 4573928..11dfb69 100644
--- a/bridge/src/android/os/Handler_Delegate.java
+++ b/bridge/src/android/os/Handler_Delegate.java
@@ -18,9 +18,13 @@
 
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
 import com.android.layoutlib.bridge.util.HandlerMessageQueue;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import java.util.WeakHashMap;
+
 /**
  * Delegate overriding selected methods of android.os.Handler
  *
@@ -32,7 +36,8 @@
 public class Handler_Delegate {
 
     // -------- Delegate methods
-    private static final HandlerMessageQueue sRunnablesQueue = new HandlerMessageQueue();
+    private static final WeakHashMap<BridgeContext, HandlerMessageQueue> sRunnablesQueues =
+            new WeakHashMap<>();
 
     @LayoutlibDelegate
     /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
@@ -42,7 +47,7 @@
             callback.sendMessageAtTime(handler, msg, uptimeMillis);
         } else {
             if (msg.callback != null) {
-                sRunnablesQueue.add(handler, uptimeMillis, msg.callback);
+                currentQueue().add(handler, uptimeMillis, msg.callback);
             }
         }
         return true;
@@ -60,7 +65,7 @@
     /*package*/ static boolean sendMessageAtFrontOfQueue(Handler handler, Message msg) {
         // We will also catch calls from the Choreographer that have no callback.
         if (msg.callback != null) {
-            sRunnablesQueue.add(handler, 0, msg.callback);
+            currentQueue().add(handler, 0, msg.callback);
         }
 
         return true;
@@ -73,17 +78,18 @@
      * @return if there are more callbacks to execute
      */
     public static boolean executeCallbacks() {
+        HandlerMessageQueue queue = currentQueue();
         try {
             long uptimeMillis = SystemClock_Delegate.uptimeMillis();
             Runnable r;
-            while ((r = sRunnablesQueue.extractFirst(uptimeMillis)) != null) {
+            while ((r = queue.extractFirst(uptimeMillis)) != null) {
                 r.run();
             }
         } catch (Throwable t) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Failed executing Handler callback", t,
                 null, null);
         }
-        return sRunnablesQueue.isNotEmpty();
+        return queue.isNotEmpty();
     }
 
     public interface IHandlerCallback {
@@ -97,7 +103,12 @@
         sCallbacks.set(callback);
     }
 
-    public static void clear() {
-        sRunnablesQueue.clear();
+    public static void dispose(BridgeContext context) {
+        sRunnablesQueues.remove(context);
+    }
+
+    private static HandlerMessageQueue currentQueue() {
+        return sRunnablesQueues.computeIfAbsent(RenderAction.getCurrentContext(),
+                c -> new HandlerMessageQueue());
     }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 9a48a34..a59a143 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -60,7 +60,7 @@
 import android.media.Image;
 import android.media.Image.Plane;
 import android.media.ImageReader;
-import android.os.Looper;
+import android.os.Handler_Delegate;
 import android.preference.Preference_Delegate;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
@@ -1189,6 +1189,7 @@
             }
             Choreographer_Delegate.dispose(getContext());
             mContentRoot = null;
+            Handler_Delegate.dispose(getContext());
         } catch (Throwable t) {
             getContext().error("Error while disposing a RenderSession", t);
         }