packages/apps/Dialer/java/com/android/voicemail/impl/scheduling/TaskQueue.java

155 lines
4.8 KiB
Java
Raw Permalink Normal View History

2025-08-25 08:38:42 +08:00
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.voicemail.impl.scheduling;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.android.voicemail.impl.Assert;
import com.android.voicemail.impl.VvmLog;
import com.android.voicemail.impl.scheduling.Task.TaskId;
import com.android.voicemail.impl.scheduling.Tasks.TaskCreationException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
/**
* A queue that manages priority and duplication of {@link Task}. A task is identified by a {@link
* TaskId}, which consists of an integer representing the operation the task, and a {@link
* android.telecom.PhoneAccountHandle} representing which SIM it is operated on.
*/
class TaskQueue implements Iterable<Task> {
private final Queue<Task> queue = new ArrayDeque<>();
public List<Bundle> toBundles() {
List<Bundle> result = new ArrayList<>(queue.size());
for (Task task : queue) {
result.add(Tasks.toBundle(task));
}
return result;
}
public void fromBundles(Context context, List<Bundle> pendingTasks) {
Assert.isTrue(queue.isEmpty());
for (Bundle pendingTask : pendingTasks) {
try {
Task task = Tasks.createTask(context, pendingTask);
task.onRestore(pendingTask);
add(task);
} catch (TaskCreationException e) {
VvmLog.e("TaskQueue.fromBundles", "cannot create task", e);
}
}
}
/**
* Add a new task to the queue. A new task with a TaskId collision will be discarded, and {@link
* Task#onDuplicatedTaskAdded(Task)} will be called on the existing task.
*
* @return {@code true} if the task is added, or {@code false} if the task is discarded due to
* collision.
*/
public boolean add(Task task) {
if (task.getId().id == Task.TASK_INVALID) {
throw new AssertionError("Task id was not set to a valid value before adding.");
}
if (task.getId().id != Task.TASK_ALLOW_DUPLICATES) {
Task oldTask = getTask(task.getId());
if (oldTask != null) {
oldTask.onDuplicatedTaskAdded(task);
VvmLog.i("TaskQueue.add", "duplicated task added");
return false;
}
}
queue.add(task);
return true;
}
public void remove(Task task) {
queue.remove(task);
}
public Task getTask(TaskId id) {
Assert.isMainThread();
for (Task task : queue) {
if (task.getId().equals(id)) {
return task;
}
}
return null;
}
/**
* Packed return value of {@link #getNextTask(long)}. If a runnable task is found {@link
* #minimalWaitTimeMillis} will be {@code null}. If no tasks is runnable {@link #task} will be
* {@code null}, and {@link #minimalWaitTimeMillis} will contain the time to wait. If there are no
* tasks at all both will be {@code null}.
*/
static final class NextTask {
@Nullable final Task task;
@Nullable final Long minimalWaitTimeMillis;
NextTask(@Nullable Task task, @Nullable Long minimalWaitTimeMillis) {
this.task = task;
this.minimalWaitTimeMillis = minimalWaitTimeMillis;
}
}
/**
* The next task is the first task with {@link Task#getReadyInMilliSeconds()} return a value less
* then {@code readyToleranceMillis}, in insertion order. If no task matches this criteria, the
* minimal value of {@link Task#getReadyInMilliSeconds()} is returned instead. If there are no
* tasks at all, the minimalWaitTimeMillis will also be null.
*/
@NonNull
NextTask getNextTask(long readyToleranceMillis) {
Long minimalWaitTime = null;
for (Task task : queue) {
long waitTime = task.getReadyInMilliSeconds();
if (waitTime < readyToleranceMillis) {
return new NextTask(task, 0L);
} else {
if (minimalWaitTime == null || waitTime < minimalWaitTime) {
minimalWaitTime = waitTime;
}
}
}
return new NextTask(null, minimalWaitTime);
}
public void clear() {
queue.clear();
}
public int size() {
return queue.size();
}
public boolean isEmpty() {
return queue.isEmpty();
}
@Override
public Iterator<Task> iterator() {
return queue.iterator();
}
}