2021-10-12 12:38:55 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2021 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;
|
|
|
|
|
|
2021-11-10 13:18:56 -08:00
|
|
|
import android.graphics.Point;
|
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
|
2021-10-12 12:38:55 -07:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
|
|
|
|
|
import com.android.launcher3.BubbleTextView;
|
|
|
|
|
import com.android.launcher3.R;
|
2021-10-19 14:47:23 -07:00
|
|
|
import com.android.launcher3.dot.FolderDotInfo;
|
|
|
|
|
import com.android.launcher3.folder.Folder;
|
|
|
|
|
import com.android.launcher3.folder.FolderIcon;
|
|
|
|
|
import com.android.launcher3.model.data.FolderInfo;
|
2021-10-12 12:38:55 -07:00
|
|
|
import com.android.launcher3.model.data.ItemInfo;
|
2021-10-19 14:47:23 -07:00
|
|
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
|
|
|
|
import com.android.launcher3.notification.NotificationListener;
|
2021-10-12 12:38:55 -07:00
|
|
|
import com.android.launcher3.popup.PopupContainerWithArrow;
|
|
|
|
|
import com.android.launcher3.popup.PopupDataProvider;
|
2021-10-19 14:47:23 -07:00
|
|
|
import com.android.launcher3.popup.PopupLiveUpdateHandler;
|
2021-10-12 12:38:55 -07:00
|
|
|
import com.android.launcher3.popup.SystemShortcut;
|
2021-11-10 13:18:56 -08:00
|
|
|
import com.android.launcher3.shortcuts.DeepShortcutView;
|
2021-10-12 12:38:55 -07:00
|
|
|
import com.android.launcher3.util.ComponentKey;
|
2021-10-19 14:47:23 -07:00
|
|
|
import com.android.launcher3.util.LauncherBindableItemsContainer;
|
|
|
|
|
import com.android.launcher3.util.PackageUserKey;
|
2021-10-12 12:38:55 -07:00
|
|
|
import com.android.launcher3.views.ActivityContext;
|
|
|
|
|
|
2021-12-15 13:09:39 -08:00
|
|
|
import java.io.PrintWriter;
|
2021-10-12 12:38:55 -07:00
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Objects;
|
2021-10-19 14:47:23 -07:00
|
|
|
import java.util.function.Predicate;
|
2021-10-12 12:38:55 -07:00
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements interfaces required to show and allow interacting with a PopupContainerWithArrow.
|
|
|
|
|
*/
|
2021-12-15 13:09:39 -08:00
|
|
|
public class TaskbarPopupController implements TaskbarControllers.LoggableTaskbarController {
|
2021-10-12 12:38:55 -07:00
|
|
|
|
|
|
|
|
private static final SystemShortcut.Factory<TaskbarActivityContext>
|
|
|
|
|
APP_INFO = SystemShortcut.AppInfo::new;
|
|
|
|
|
|
2021-10-19 14:47:23 -07:00
|
|
|
private final TaskbarActivityContext mContext;
|
2021-10-12 12:38:55 -07:00
|
|
|
private final PopupDataProvider mPopupDataProvider;
|
|
|
|
|
|
2021-10-19 14:47:23 -07:00
|
|
|
// Initialized in init.
|
|
|
|
|
private TaskbarControllers mControllers;
|
|
|
|
|
|
|
|
|
|
public TaskbarPopupController(TaskbarActivityContext context) {
|
|
|
|
|
mContext = context;
|
|
|
|
|
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void init(TaskbarControllers controllers) {
|
|
|
|
|
mControllers = controllers;
|
|
|
|
|
|
|
|
|
|
NotificationListener.addNotificationsChangedListener(mPopupDataProvider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onDestroy() {
|
|
|
|
|
NotificationListener.removeNotificationsChangedListener(mPopupDataProvider);
|
2021-10-12 12:38:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
public PopupDataProvider getPopupDataProvider() {
|
|
|
|
|
return mPopupDataProvider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
|
|
|
|
|
mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-19 14:47:23 -07:00
|
|
|
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
|
|
|
|
final PackageUserKey packageUserKey = new PackageUserKey(null, null);
|
|
|
|
|
Predicate<ItemInfo> matcher = info -> !packageUserKey.updateFromItemInfo(info)
|
|
|
|
|
|| updatedDots.test(packageUserKey);
|
|
|
|
|
|
|
|
|
|
LauncherBindableItemsContainer.ItemOperator op = (info, v) -> {
|
|
|
|
|
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView) {
|
|
|
|
|
if (matcher.test(info)) {
|
|
|
|
|
((BubbleTextView) v).applyDotState(info, true /* animate */);
|
|
|
|
|
}
|
|
|
|
|
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
|
|
|
|
|
FolderInfo fi = (FolderInfo) info;
|
|
|
|
|
if (fi.contents.stream().anyMatch(matcher)) {
|
|
|
|
|
FolderDotInfo folderDotInfo = new FolderDotInfo();
|
|
|
|
|
for (WorkspaceItemInfo si : fi.contents) {
|
|
|
|
|
folderDotInfo.addDotInfo(mPopupDataProvider.getDotInfoForItem(si));
|
|
|
|
|
}
|
|
|
|
|
((FolderIcon) v).setDotInfo(folderDotInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// process all the shortcuts
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mControllers.taskbarViewController.mapOverItems(op);
|
|
|
|
|
Folder folder = Folder.getOpen(mContext);
|
|
|
|
|
if (folder != null) {
|
|
|
|
|
folder.iterateOverItems(op);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-12 12:38:55 -07:00
|
|
|
/**
|
|
|
|
|
* Shows the notifications and deep shortcuts associated with a Taskbar {@param icon}.
|
|
|
|
|
* @return the container if shown or null.
|
|
|
|
|
*/
|
|
|
|
|
public PopupContainerWithArrow<TaskbarActivityContext> showForIcon(BubbleTextView icon) {
|
|
|
|
|
TaskbarActivityContext context = ActivityContext.lookupContext(icon.getContext());
|
|
|
|
|
if (PopupContainerWithArrow.getOpen(context) != null) {
|
|
|
|
|
// There is already an items container open, so don't open this one.
|
|
|
|
|
icon.clearFocus();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
ItemInfo item = (ItemInfo) icon.getTag();
|
|
|
|
|
if (!PopupContainerWithArrow.canShow(icon, item)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final PopupContainerWithArrow<TaskbarActivityContext> container =
|
|
|
|
|
(PopupContainerWithArrow) context.getLayoutInflater().inflate(
|
|
|
|
|
R.layout.popup_container, context.getDragLayer(), false);
|
2021-10-19 14:47:23 -07:00
|
|
|
container.addOnAttachStateChangeListener(
|
2021-11-10 13:18:56 -08:00
|
|
|
new PopupLiveUpdateHandler<TaskbarActivityContext>(mContext, container) {
|
|
|
|
|
@Override
|
|
|
|
|
protected void showPopupContainerForIcon(BubbleTextView originalIcon) {
|
|
|
|
|
showForIcon(originalIcon);
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-10-12 12:38:55 -07:00
|
|
|
// TODO (b/198438631): configure for taskbar/context
|
2021-11-10 13:18:56 -08:00
|
|
|
container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
|
2021-10-12 12:38:55 -07:00
|
|
|
|
|
|
|
|
container.populateAndShow(icon,
|
|
|
|
|
mPopupDataProvider.getShortcutCountForItem(item),
|
|
|
|
|
mPopupDataProvider.getNotificationKeysForItem(item),
|
|
|
|
|
// TODO (b/198438631): add support for INSTALL shortcut factory
|
|
|
|
|
Stream.of(APP_INFO)
|
|
|
|
|
.map(s -> s.getShortcut(context, item))
|
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
|
.collect(Collectors.toList()));
|
|
|
|
|
container.requestFocus();
|
2022-01-12 14:33:43 -08:00
|
|
|
|
|
|
|
|
// Make focusable to receive back events
|
|
|
|
|
mControllers.taskbarActivityContext.setTaskbarWindowFocusable(true);
|
|
|
|
|
container.setOnCloseCallback(() -> {
|
|
|
|
|
mControllers.taskbarActivityContext.getDragLayer().post(
|
|
|
|
|
() -> mControllers.taskbarActivityContext.setTaskbarWindowFocusable(false));
|
|
|
|
|
container.setOnCloseCallback(null);
|
|
|
|
|
});
|
|
|
|
|
|
2021-10-12 12:38:55 -07:00
|
|
|
return container;
|
|
|
|
|
}
|
2021-11-10 13:18:56 -08:00
|
|
|
|
2021-12-15 13:09:39 -08:00
|
|
|
@Override
|
|
|
|
|
public void dumpLogs(String prefix, PrintWriter pw) {
|
|
|
|
|
pw.println(prefix + "TaskbarPopupController:");
|
|
|
|
|
|
|
|
|
|
mPopupDataProvider.dump(prefix + "\t", pw);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 13:18:56 -08:00
|
|
|
private class TaskbarPopupItemDragHandler implements
|
|
|
|
|
PopupContainerWithArrow.PopupItemDragHandler {
|
|
|
|
|
|
|
|
|
|
protected final Point mIconLastTouchPos = new Point();
|
|
|
|
|
|
|
|
|
|
TaskbarPopupItemDragHandler() {}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onTouch(View view, MotionEvent ev) {
|
|
|
|
|
// Touched a shortcut, update where it was touched so we can drag from there on
|
|
|
|
|
// long click.
|
|
|
|
|
switch (ev.getAction()) {
|
|
|
|
|
case MotionEvent.ACTION_DOWN:
|
|
|
|
|
case MotionEvent.ACTION_MOVE:
|
|
|
|
|
mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onLongClick(View v) {
|
|
|
|
|
// Return early if not the correct view
|
|
|
|
|
if (!(v.getParent() instanceof DeepShortcutView)) return false;
|
|
|
|
|
|
|
|
|
|
DeepShortcutView sv = (DeepShortcutView) v.getParent();
|
|
|
|
|
sv.setWillDrawIcon(false);
|
|
|
|
|
|
|
|
|
|
// Move the icon to align with the center-top of the touch point
|
|
|
|
|
Point iconShift = new Point();
|
|
|
|
|
iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
|
|
|
|
|
iconShift.y = mIconLastTouchPos.y - mContext.getDeviceProfile().iconSizePx;
|
|
|
|
|
|
|
|
|
|
mControllers.taskbarDragController.startDragOnLongClick(sv, iconShift);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-12 12:38:55 -07:00
|
|
|
}
|