package com.osama.firecrasher;

import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by osama.
 */


public class FireLooper implements Runnable {
    private static final Object EXIT = new Object();
    private static final ThreadLocal<FireLooper> RUNNINGS = new ThreadLocal<>();
    private static Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
    private static Handler handler = new Handler(Looper.getMainLooper());

    public static void install() {
        handler.removeMessages(0, EXIT);
        handler.post(new FireLooper());
    }

    public static void uninstallDelay(long millis) {
        handler.removeMessages(0, EXIT);
        handler.sendMessageDelayed(handler.obtainMessage(0, EXIT), millis);
    }

    public static void uninstall() {
        uninstallDelay(0);
    }

    public static boolean isSafe() {
        return RUNNINGS.get() != null;
    }

    public static void setUncaughtExceptionHandler(
            Thread.UncaughtExceptionHandler h) {
        uncaughtExceptionHandler = h;
    }

    @Override
    public void run() {
        if (RUNNINGS.get() != null)
            return;

        Method next;
        Field target;
        try {
            Method m = MessageQueue.class.getDeclaredMethod("next");
            m.setAccessible(true);
            next = m;
            Field f = Message.class.getDeclaredField("target");
            f.setAccessible(true);
            target = f;
        } catch (Exception e) {
            return;
        }

        RUNNINGS.set(this);
        MessageQueue queue = Looper.myQueue();
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        while (true) {
            try {
                Message msg = (Message) next.invoke(queue);
                if (msg == null || msg.obj == EXIT)
                    break;

                Handler h = (Handler) target.get(msg);
                    h.dispatchMessage(msg);


                final long newIdent = Binder.clearCallingIdentity();

                int currentapiVersion = android.os.Build.VERSION.SDK_INT;
                if (currentapiVersion < android.os.Build.VERSION_CODES.LOLLIPOP){
                    msg.recycle();
                }
            } catch (Exception e) {
                Thread.UncaughtExceptionHandler h = uncaughtExceptionHandler;
                Throwable ex = e;
                if (e instanceof InvocationTargetException) {
                    ex = e.getCause();
                    if (ex == null) {
                        ex = e;
                    }
                }

                if (h != null) {
                    h.uncaughtException(Thread.currentThread(), ex);
                }
                new Handler().post(this);
                break;
            }
        }

        RUNNINGS.set(null);
    }
}

@@ -2183,30 +2183,8 @@
     
- final long newIdent =
  Bin
@@ -2203,32 +2203,32 @@
 lingIdentity();%0A
+
 %0A               
@@ -2413,32 +2413,32 @@
               %7D%0A
-
             %7D ca
@@ -2433,32 +2433,592 @@
         %7D catch 
+(InvocationTargetException e) %7B%0A                Thread.UncaughtExceptionHandler h = uncaughtExceptionHandler;%0A                Throwable ex = e;%0A                if (e instanceof InvocationTargetException) %7B%0A                    ex = e.getCause();%0A                    if (ex == null) %7B%0A                        ex = e;%0A                    %7D%0A                %7D%0A%0A                if (h != null) %7B%0A                    h.uncaughtException(Thread.currentThread(), ex);%0A                %7D%0A                new Handler().post(this);%0A                break;%0A            %7Dcatch 
 (Exception e) %7B%0A

Update FireLooper.java