That fuck shit the fascists are using
at master 134 lines 4.0 kB view raw
1package org.tm.archive.service; 2 3import android.os.Handler; 4import android.os.Looper; 5 6import androidx.annotation.NonNull; 7import androidx.annotation.Nullable; 8 9import org.signal.core.util.concurrent.SignalExecutors; 10import org.signal.core.util.logging.Log; 11 12import java.util.Objects; 13 14/** 15 * Represents a delayed foreground notification. 16 * <p> 17 * With this, you can {@link #close()} it to dismiss or prevent it showing if it hasn't already. 18 * <p> 19 * You can also {@link #showNow()} to show if it's not already. This returns a regular {@link NotificationController} which can be updated if required. 20 */ 21public abstract class DelayedNotificationController implements AutoCloseable { 22 23 private static final String TAG = Log.tag(DelayedNotificationController.class); 24 25 public static final long SHOW_WITHOUT_DELAY = 0; 26 public static final long DO_NOT_SHOW = -1; 27 28 private DelayedNotificationController() {} 29 30 static DelayedNotificationController create(long delayMillis, @NonNull Create createTask) { 31 if (delayMillis == SHOW_WITHOUT_DELAY) return new Shown(createTask.create()); 32 if (delayMillis == DO_NOT_SHOW) return new NoShow(); 33 if (delayMillis > 0) return new DelayedShow(delayMillis, createTask); 34 35 throw new IllegalArgumentException("Illegal delay " + delayMillis); 36 } 37 38 /** 39 * Show the foreground notification if it's not already showing. 40 * <p> 41 * If it does show, it returns a regular {@link NotificationController} which you can use to update its message or progress. 42 */ 43 public abstract @Nullable NotificationController showNow(); 44 45 @Override 46 public void close() { 47 } 48 49 private static final class NoShow extends DelayedNotificationController { 50 51 @Override 52 public @Nullable NotificationController showNow() { 53 return null; 54 } 55 } 56 57 private static final class Shown extends DelayedNotificationController { 58 59 private final NotificationController controller; 60 61 Shown(@NonNull NotificationController controller) { 62 this.controller = controller; 63 } 64 65 @Override 66 public void close() { 67 this.controller.close(); 68 } 69 70 @Override 71 public NotificationController showNow() { 72 return controller; 73 } 74 } 75 76 private static final class DelayedShow extends DelayedNotificationController { 77 78 private final Create createTask; 79 private final Handler handler; 80 private final Runnable start; 81 private NotificationController notificationController; 82 private boolean isClosed; 83 84 private DelayedShow(long delayMillis, @NonNull Create createTask) { 85 this.createTask = createTask; 86 this.handler = new Handler(Looper.getMainLooper()); 87 this.start = this::start; 88 89 handler.postDelayed(start, delayMillis); 90 } 91 92 private void start() { 93 SignalExecutors.BOUNDED.execute(this::showNowInner); 94 } 95 96 public synchronized @NonNull NotificationController showNow() { 97 if (isClosed) { 98 throw new AssertionError("showNow called after close"); 99 } 100 return Objects.requireNonNull(showNowInner()); 101 } 102 103 private synchronized @Nullable NotificationController showNowInner() { 104 if (notificationController != null) { 105 return notificationController; 106 } 107 108 if (!isClosed) { 109 Log.i(TAG, "Starting foreground service"); 110 notificationController = createTask.create(); 111 return notificationController; 112 } else { 113 Log.i(TAG, "Did not start foreground service as close has been called"); 114 return null; 115 } 116 } 117 118 @Override 119 public synchronized void close() { 120 handler.removeCallbacks(start); 121 isClosed = true; 122 if (notificationController != null) { 123 Log.d(TAG, "Closing"); 124 notificationController.close(); 125 } else { 126 Log.d(TAG, "Never showed"); 127 } 128 } 129 } 130 131 public interface Create { 132 @NonNull NotificationController create(); 133 } 134}