1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.safetycenter; 18 19 import android.os.Handler; 20 21 import com.android.permission.util.ForegroundThread; 22 23 import java.io.PrintWriter; 24 import java.time.Duration; 25 import java.util.ArrayDeque; 26 import java.util.Iterator; 27 28 import javax.annotation.concurrent.NotThreadSafe; 29 30 /** 31 * A class to track timeouts related to Safety Center. 32 * 33 * <p>This class isn't thread safe. Thread safety must be handled by the caller. 34 */ 35 @NotThreadSafe 36 final class SafetyCenterTimeouts { 37 38 /** 39 * The maximum number of timeouts we are tracking at a given time. This is to avoid having the 40 * {@code mTimeouts} queue grow unbounded. In practice, we should never have more than 1 or 2 41 * timeouts in flight. 42 */ 43 private static final int MAX_TRACKED = 10; 44 45 private final ArrayDeque<Runnable> mTimeouts = new ArrayDeque<>(MAX_TRACKED); 46 47 private final Handler mForegroundHandler = ForegroundThread.getHandler(); 48 SafetyCenterTimeouts()49 SafetyCenterTimeouts() {} 50 51 /** Adds the given {@link Runnable} to run as a timeout after the given {@link Duration}. */ add(Runnable timeoutAction, Duration timeoutDuration)52 void add(Runnable timeoutAction, Duration timeoutDuration) { 53 if (mTimeouts.size() + 1 >= MAX_TRACKED) { 54 remove(mTimeouts.pollFirst()); 55 } 56 mTimeouts.addLast(timeoutAction); 57 mForegroundHandler.postDelayed(timeoutAction, timeoutDuration.toMillis()); 58 } 59 60 /** Removes the given {@link Runnable} to run as a timeout. */ remove(Runnable timeoutAction)61 void remove(Runnable timeoutAction) { 62 mTimeouts.remove(timeoutAction); 63 mForegroundHandler.removeCallbacks(timeoutAction); 64 } 65 66 /** Clears all timeouts. */ clear()67 void clear() { 68 while (!mTimeouts.isEmpty()) { 69 mForegroundHandler.removeCallbacks(mTimeouts.pollFirst()); 70 } 71 } 72 73 /** Dumps state for debugging purposes. */ dump(PrintWriter fout)74 void dump(PrintWriter fout) { 75 int count = mTimeouts.size(); 76 fout.println("TIMEOUTS (" + count + ")"); 77 Iterator<Runnable> it = mTimeouts.iterator(); 78 int i = 0; 79 while (it.hasNext()) { 80 fout.println("\t[" + i++ + "] " + it.next()); 81 } 82 fout.println(); 83 } 84 } 85