Files
lawnchair/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java

201 lines
7.4 KiB
Java
Raw Normal View History

/*
* Copyright (C) 2023 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.launcher3.taskbar;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.animation.Animator;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.PrintWriter;
import java.util.List;
import java.util.function.Consumer;
/**
* Handles initialization of the {@link KeyboardQuickSwitchView} and supplies it with the list of
* tasks.
*/
public class KeyboardQuickSwitchViewController {
@NonNull private final ViewCallbacks mViewCallbacks = new ViewCallbacks();
@NonNull private final TaskbarControllers mControllers;
@NonNull private final TaskbarOverlayContext mOverlayContext;
@NonNull private final KeyboardQuickSwitchView mKeyboardQuickSwitchView;
@NonNull private final KeyboardQuickSwitchController.ControllerCallbacks mControllerCallbacks;
@Nullable private Animator mCloseAnimation;
private int mCurrentFocusIndex = -1;
protected KeyboardQuickSwitchViewController(
@NonNull TaskbarControllers controllers,
@NonNull TaskbarOverlayContext overlayContext,
@NonNull KeyboardQuickSwitchView keyboardQuickSwitchView,
@NonNull KeyboardQuickSwitchController.ControllerCallbacks controllerCallbacks) {
mControllers = controllers;
mOverlayContext = overlayContext;
mKeyboardQuickSwitchView = keyboardQuickSwitchView;
mControllerCallbacks = controllerCallbacks;
}
protected int getCurrentFocusedIndex() {
return mCurrentFocusIndex;
}
protected void openQuickSwitchView(
@NonNull List<GroupTask> tasks,
int numHiddenTasks,
boolean updateTasks,
int currentFocusIndexOverride) {
TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
dragLayer.addView(mKeyboardQuickSwitchView);
dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
mKeyboardQuickSwitchView.applyLoadPlan(
mOverlayContext,
tasks,
numHiddenTasks,
updateTasks,
currentFocusIndexOverride,
mViewCallbacks);
}
protected void closeQuickSwitchView(boolean animate) {
if (mCloseAnimation != null) {
if (animate) {
// Let currently-running animation finish.
return;
} else {
mCloseAnimation.cancel();
}
}
if (!animate) {
mCloseAnimation = null;
onCloseComplete();
return;
}
mCloseAnimation = mKeyboardQuickSwitchView.getCloseAnimation();
mCloseAnimation.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
mCloseAnimation = null;
onCloseComplete();
}
});
mCloseAnimation.start();
}
/**
* Launched the currently-focused task.
*
* Returns index -1 iff the RecentsView shouldn't be opened.
*
* If the index is not -1, then the {@link com.android.quickstep.views.TaskView} at the returned
* index will be focused.
*/
protected int launchFocusedTask() {
// Launch the second-most recent task if the user quick switches too quickly, if possible.
return launchTaskAt(mCurrentFocusIndex == -1
? (mControllerCallbacks.getTaskCount() > 1 ? 1 : 0) : mCurrentFocusIndex);
}
private int launchTaskAt(int index) {
KeyboardQuickSwitchTaskView taskView = mKeyboardQuickSwitchView.getTaskAt(index);
GroupTask task = mControllerCallbacks.getTaskAt(index);
if (taskView == null || task == null) {
return Math.max(0, index);
} else if (task.task2 == null) {
UI_HELPER_EXECUTOR.execute(() ->
ActivityManagerWrapper.getInstance().startActivityFromRecents(
task.task1.key,
mControllers.taskbarActivityContext.getActivityLaunchOptions(
taskView, null).options));
} else {
mControllers.uiController.launchSplitTasks(taskView, task);
}
return -1;
}
private void onCloseComplete() {
mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView);
mControllerCallbacks.onCloseComplete();
}
protected void onDestroy() {
closeQuickSwitchView(false);
}
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "KeyboardQuickSwitchViewController:");
pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
pw.println(prefix + "\tcloseAnimationRunning=" + (mCloseAnimation != null));
pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
}
class ViewCallbacks {
boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode != KeyEvent.KEYCODE_TAB) {
return false;
}
int taskCount = mControllerCallbacks.getTaskCount();
int toIndex = mCurrentFocusIndex == -1
// Focus the second-most recent app if possible
? (taskCount > 1 ? 1 : 0)
: (event.isShiftPressed()
// focus a more recent task or loop back to the opposite end
? Math.max(0, mCurrentFocusIndex == 0
? taskCount - 1 : mCurrentFocusIndex - 1)
// focus a less recent app or loop back to the opposite end
: ((mCurrentFocusIndex + 1) % taskCount));
mKeyboardQuickSwitchView.animateFocusMove(mCurrentFocusIndex, toIndex);
return true;
}
void updateCurrentFocusIndex(int index) {
mCurrentFocusIndex = index;
}
void launchTappedTask(int index) {
KeyboardQuickSwitchViewController.this.launchTaskAt(index);
closeQuickSwitchView(true);
}
void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
mControllerCallbacks.updateThumbnailInBackground(task, callback);
}
void updateTitleInBackground(Task task, Consumer<Task> callback) {
mControllerCallbacks.updateTitleInBackground(task, callback);
}
}
}