package ee.ria.DigiDoc.smartcardreader;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.util.Log;

import androidx.annotation.Nullable;

import com.google.common.base.Optional;

import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import timber.log.Timber;

final class SmartCardReaderOnSubscribe implements ObservableOnSubscribe<Optional<SmartCardReader>> {

    private static final String ACTION_USB_DEVICE_PERMISSION = BuildConfig.LIBRARY_PACKAGE_NAME +
            ".USB_DEVICE_PERMISSION";

    private final Context context;
    private final UsbManager usbManager;
    private final SmartCardReaderManager smartCardReaderManager;

    @Nullable private UsbDevice currentDevice;
    @Nullable private SmartCardReader currentReader;

    SmartCardReaderOnSubscribe(Context context, SmartCardReaderManager smartCardReaderManager) {
        this.context = context;
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        this.smartCardReaderManager = smartCardReaderManager;
    }

    @Override
    public void subscribe(ObservableEmitter<Optional<SmartCardReader>> emitter) {
        BroadcastReceiver deviceAttachReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                Timber.log(Log.DEBUG, "Smart card device attached: %s", device);
                if (smartCardReaderManager.supports(device)) {
                    requestPermission(device);
                }
            }
        };
        BroadcastReceiver deviceDetachReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                Timber.log(Log.DEBUG, "Smart card device detached: %s", device);
                if (currentDevice != null && currentDevice.getDeviceId() == device.getDeviceId()) {
                    clearCurrent();
                    emitter.onNext(Optional.absent());
                }
            }
        };
        BroadcastReceiver devicePermissionReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                boolean permissionGranted = intent.getBooleanExtra(
                        UsbManager.EXTRA_PERMISSION_GRANTED, false);
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                Timber.log(Log.DEBUG, "Smart card device permission: granted: %s; device: %s", permissionGranted,
                        device);
                if (permissionGranted && smartCardReaderManager.supports(device)) {
                    clearCurrent();
                    currentDevice = device;
                    currentReader = smartCardReaderManager.reader(device);
                    emitter.onNext(Optional.fromNullable(currentReader));
                }
            }
        };

        context.registerReceiver(deviceAttachReceiver,
                new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
        context.registerReceiver(deviceDetachReceiver,
                new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
        context.registerReceiver(devicePermissionReceiver,
                new IntentFilter(ACTION_USB_DEVICE_PERMISSION));

        emitter.setCancellable(() -> {
            context.unregisterReceiver(deviceAttachReceiver);
            context.unregisterReceiver(deviceDetachReceiver);
            context.unregisterReceiver(devicePermissionReceiver);
            clearCurrent();
        });

        for (UsbDevice device : usbManager.getDeviceList().values()) {
            if (smartCardReaderManager.supports(device)) {
                requestPermission(device);
                break;
            }
        }
    }

    private void requestPermission(UsbDevice device) {
        usbManager.requestPermission(device,
                PendingIntent
                        .getBroadcast(context, 0, new Intent(ACTION_USB_DEVICE_PERMISSION), 0));
    }

    private void clearCurrent() {
        currentDevice = null;
        if (currentReader != null) {
            try {
                currentReader.close();
            } catch (Exception e) {
                Timber.log(Log.ERROR, e, "Closing current reader %s", currentReader);
            }
            currentReader = null;
        }
    }
}

@@ -285,24 +285,49 @@
 UsbManager;%0A
+import android.os.Build;%0A
 import andro
@@ -4292,24 +4292,90 @@
 e device) %7B%0A
+        if (Build.VERSION.SDK_INT %3E= Build.VERSION_CODES.S) %7B%0A    
         usbM
@@ -4423,16 +4423,20 @@
         
+    
 PendingI
@@ -4441,16 +4441,246 @@
 gIntent%0A
+                            .getBroadcast(context, 0, new Intent(ACTION_USB_DEVICE_PERMISSION), PendingIntent.FLAG_MUTABLE));%0A        %7D else %7B%0A            usbManager.requestPermission(device,%0A                    PendingIntent%0A    
         
@@ -4764,24 +4764,34 @@
 SION), 0));%0A
+        %7D%0A
     %7D%0A%0A    p

Fix Android 12 crash