Merge changes I6bf48141,I77b7a2e4 into sc-v2-dev

* changes:
  Taskbar drag starts internal pre-drag before system drag
  Let DragView use ActivityContext instead of Launcher
This commit is contained in:
Tony Wickham
2021-05-26 17:13:49 +00:00
committed by Android (Google) Code Review
18 changed files with 512 additions and 190 deletions
@@ -222,7 +222,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
public boolean isDraggingItem() {
return mTaskbarView.isDraggingItem();
return mContext.getDragController().isDragging();
}
/**
@@ -28,9 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.SystemProperties;
import android.util.Log;
@@ -43,22 +41,14 @@ import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
import com.android.launcher3.touch.ItemClickHandler;
@@ -89,10 +79,13 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private final LayoutInflater mLayoutInflater;
private final TaskbarDragLayer mDragLayer;
private final TaskbarIconController mIconController;
private final MyDragController mDragController;
private final TaskbarDragController mDragController;
private final WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowLayoutParams;
private boolean mIsFullscreen;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
private int mLastRequestedNonFullscreenHeight;
private final SysUINavigationMode.Mode mNavMode;
private final TaskbarNavButtonController mNavButtonController;
@@ -114,8 +107,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
() -> getPackageManager().isSafeMode());
mOnTaskbarIconLongClickListener =
new TaskbarDragController(this)::startSystemDragOnLongClick;
mDragController = new TaskbarDragController(this);
mOnTaskbarIconLongClickListener = mDragController::startDragOnLongClick;
mOnTaskbarIconClickListener = this::onTaskbarIconClicked;
float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
@@ -126,7 +119,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mDragLayer = (TaskbarDragLayer) mLayoutInflater
.inflate(R.layout.taskbar, null, false);
mIconController = new TaskbarIconController(this, mDragLayer);
mDragController = new MyDragController(this);
Display display = windowContext.getDisplay();
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
@@ -136,9 +128,10 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
}
public void init() {
mLastRequestedNonFullscreenHeight = mDeviceProfile.taskbarSize;
mWindowLayoutParams = new WindowManager.LayoutParams(
MATCH_PARENT,
mDeviceProfile.taskbarSize,
mLastRequestedNonFullscreenHeight,
TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
@@ -160,17 +153,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
}
/**
* Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
*/
public void setTaskbarWindowHeight(int height) {
if (mWindowLayoutParams.height == height) {
return;
}
mWindowLayoutParams.height = height;
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
public boolean canShowNavButtons() {
return ENABLE_THREE_BUTTON_TASKBAR && mNavMode == Mode.THREE_BUTTONS;
}
@@ -196,7 +178,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
}
@Override
public DragController getDragController() {
public TaskbarDragController getDragController() {
return mDragController;
}
@@ -243,8 +225,30 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
/**
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
protected void setTaskbarWindowFullscreen(boolean fullscreen) {
setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : getDeviceProfile().taskbarSize);
public void setTaskbarWindowFullscreen(boolean fullscreen) {
mIsFullscreen = fullscreen;
setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
}
/**
* Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
*/
public void setTaskbarWindowHeight(int height) {
if (mWindowLayoutParams.height == height) {
return;
}
if (height != MATCH_PARENT) {
mLastRequestedNonFullscreenHeight = height;
if (mIsFullscreen) {
// We still need to be fullscreen, so defer any change to our height until we call
// setTaskbarWindowFullscreen(false). For example, this could happen when dragging
// from the gesture region, as the drag will cancel the gesture and reset launcher's
// state, which in turn normally would reset the taskbar window height as well.
return;
}
}
mWindowLayoutParams.height = height;
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
protected void onTaskbarIconClicked(View view) {
@@ -309,27 +313,4 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
AbstractFloatingView.closeAllOpenViews(this);
}
private static class MyDragController extends DragController<TaskbarActivityContext> {
MyDragController(TaskbarActivityContext activity) {
super(activity);
}
@Override
protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
float dragViewScaleOnDrop, DragOptions options) {
return null;
}
@Override
protected void exitDrag() {
}
@Override
protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
return null;
}
}
}
@@ -20,19 +20,35 @@ import static android.view.View.VISIBLE;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragDriver;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ClipDescriptionCompat;
@@ -41,14 +57,20 @@ import com.android.systemui.shared.system.LauncherAppsCompat;
/**
* Handles long click on Taskbar items to start a system drag and drop operation.
*/
public class TaskbarDragController {
public class TaskbarDragController extends DragController<TaskbarActivityContext> {
private final Context mContext;
private final int mDragIconSize;
private final int[] mTempXY = new int[2];
public TaskbarDragController(Context context) {
mContext = context;
Resources resources = mContext.getResources();
// Where the initial touch was relative to the dragged icon.
private int mRegistrationX;
private int mRegistrationY;
private boolean mIsSystemDragInProgress;
public TaskbarDragController(TaskbarActivityContext activity) {
super(activity);
Resources resources = mActivity.getResources();
mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size);
}
@@ -57,18 +79,146 @@ public class TaskbarDragController {
* generate the ClipDescription and Intent.
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
protected boolean startSystemDragOnLongClick(View view) {
protected boolean startDragOnLongClick(View view) {
if (!(view instanceof BubbleTextView)) {
return false;
}
BubbleTextView btv = (BubbleTextView) view;
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) {
mActivity.setTaskbarWindowFullscreen(true);
view.post(() -> {
startInternalDrag(btv);
btv.setVisibility(INVISIBLE);
});
return true;
}
private void startInternalDrag(BubbleTextView btv) {
float iconScale = 1f;
Drawable icon = btv.getIcon();
if (icon instanceof FastBitmapDrawable) {
iconScale = ((FastBitmapDrawable) icon).getAnimatedScale();
}
// Clear the pressed state if necessary
btv.clearFocus();
btv.setPressed(false);
btv.clearPressedBackground();
final DragPreviewProvider previewProvider = new DragPreviewProvider(btv);
final Drawable drawable = previewProvider.createDrawable();
final float scale = previewProvider.getScaleAndPosition(drawable, mTempXY);
int dragLayerX = mTempXY[0];
int dragLayerY = mTempXY[1];
Rect dragRect = new Rect();
btv.getSourceVisualDragBounds(dragRect);
dragLayerY += dragRect.top;
DragOptions dragOptions = new DragOptions();
// TODO: open popup/pre-drag
// PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon(view);
// if (popupContainer != null) {
// dragOptions.preDragCondition = popupContainer.createPreDragCondition();
// }
startDrag(
drawable,
/* view = */ null,
/* originalView = */ btv,
dragLayerX,
dragLayerY,
(View target, DropTarget.DragObject d, boolean success) -> {} /* DragSource */,
(WorkspaceItemInfo) btv.getTag(),
/* dragVisualizeOffset = */ null,
dragRect,
scale * iconScale,
scale,
dragOptions);
}
@Override
protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
float dragViewScaleOnDrop, DragOptions options) {
mOptions = options;
mRegistrationX = mMotionDown.x - dragLayerX;
mRegistrationY = mMotionDown.y - dragLayerY;
final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
mLastDropTarget = null;
mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
mDragObject.originalView = originalView;
mIsInPreDrag = mOptions.preDragCondition != null
&& !mOptions.preDragCondition.shouldStartDrag(0);
float scalePx = mDragIconSize - dragRegion.width();
final DragView dragView = mDragObject.dragView = new TaskbarDragView(
mActivity,
drawable,
mRegistrationX,
mRegistrationY,
initialDragViewScale,
dragViewScaleOnDrop,
scalePx);
dragView.setItemInfo(dragInfo);
mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
mDragDriver = DragDriver.create(this, mOptions, /* secondaryEventConsumer = */ ev -> {});
if (!mOptions.isAccessibleDrag) {
mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
}
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
if (dragRegion != null) {
dragView.setDragRegion(new Rect(dragRegion));
}
dragView.show(mLastTouch.x, mLastTouch.y);
mDistanceSinceScroll = 0;
if (!mIsInPreDrag) {
callOnDragStart();
} else if (mOptions.preDragCondition != null) {
mOptions.preDragCondition.onPreDragStart(mDragObject);
}
handleMoveEvent(mLastTouch.x, mLastTouch.y);
return dragView;
}
@Override
protected void callOnDragStart() {
super.callOnDragStart();
// Pre-drag has ended, start the global system drag.
AbstractFloatingView.closeAllOpenViews(mActivity);
startSystemDrag((BubbleTextView) mDragObject.originalView);
}
private void startSystemDrag(BubbleTextView btv) {
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(btv) {
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
shadowSize.set(mDragIconSize, mDragIconSize);
// TODO: should be based on last touch point on the icon.
shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
// The registration point was taken before the icon scaled to mDragIconSize, so
// offset the registration to where the touch is on the new size.
int offset = (mDragIconSize - btv.getIconSize()) / 2;
shadowTouchPoint.set(mRegistrationX + offset, mRegistrationY + offset);
}
@Override
@@ -81,12 +231,12 @@ public class TaskbarDragController {
}
};
Object tag = view.getTag();
Object tag = btv.getTag();
ClipDescription clipDescription = null;
Intent intent = null;
if (tag instanceof WorkspaceItemInfo) {
WorkspaceItemInfo item = (WorkspaceItemInfo) tag;
LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
LauncherApps launcherApps = mActivity.getSystemService(LauncherApps.class);
clipDescription = new ClipDescription(item.title,
new String[] {
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
@@ -116,28 +266,89 @@ public class TaskbarDragController {
if (clipDescription != null && intent != null) {
ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
view.setOnDragListener(getDraggedViewDragListener());
return view.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE);
if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE)) {
onSystemDragStarted();
}
}
return false;
}
/**
* Hide the original Taskbar item while it is being dragged.
*/
private View.OnDragListener getDraggedViewDragListener() {
return (view, dragEvent) -> {
private void onSystemDragStarted() {
mIsSystemDragInProgress = true;
mActivity.getDragLayer().setOnDragListener((view, dragEvent) -> {
switch (dragEvent.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
view.setVisibility(INVISIBLE);
// Return true to tell system we are interested in events, so we get DRAG_ENDED.
return true;
case DragEvent.ACTION_DRAG_ENDED:
view.setVisibility(VISIBLE);
view.setOnDragListener(null);
mIsSystemDragInProgress = false;
maybeOnDragEnd();
return true;
}
return false;
};
});
}
@Override
public boolean isDragging() {
return super.isDragging() || mIsSystemDragInProgress;
}
/**
* Whether we started dragging the given view and the drag is still in progress.
*/
public boolean isDraggingView(View child) {
return isDragging() && mDragObject != null && mDragObject.originalView == child;
}
private void maybeOnDragEnd() {
if (!isDragging()) {
((View) mDragObject.originalView).setVisibility(VISIBLE);
}
}
@Override
protected void callOnDragEnd() {
super.callOnDragEnd();
maybeOnDragEnd();
}
@Override
protected float getX(MotionEvent ev) {
// We will resize to fill the screen while dragging, so use screen coordinates. This ensures
// we start at the correct position even though touch down is on the smaller DragLayer size.
return ev.getRawX();
}
@Override
protected float getY(MotionEvent ev) {
// We will resize to fill the screen while dragging, so use screen coordinates. This ensures
// we start at the correct position even though touch down is on the smaller DragLayer size.
return ev.getRawY();
}
@Override
protected Point getClampedDragLayerPos(float x, float y) {
// No need to clamp, as we will take up the entire screen.
mTmpPoint.set(Math.round(x), Math.round(y));
return mTmpPoint;
}
@Override
protected void exitDrag() {
if (mDragObject != null) {
mActivity.getDragLayer().removeView(mDragObject.dragView);
}
}
@Override
public void addDropTarget(DropTarget target) {
// No-op as Taskbar currently doesn't support any drop targets internally.
// Note: if we do add internal DropTargets, we'll still need to ignore Folder.
}
@Override
protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
return null;
}
}
@@ -40,7 +40,7 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
private final int mFolderMargin;
private final Paint mTaskbarBackgroundPaint;
private TaskbarIconController.Callbacks mControllerCallbacks;
private TaskbarIconController.TaskbarDragLayerCallbacks mControllerCallbacks;
private TaskbarView mTaskbarView;
private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets;
@@ -69,10 +69,11 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
@Override
public void recreateControllers() {
mControllers = new TouchController[0];
mControllers = new TouchController[] {mActivity.getDragController()};
}
public void init(TaskbarIconController.Callbacks callbacks, TaskbarView taskbarView) {
public void init(TaskbarIconController.TaskbarDragLayerCallbacks callbacks,
TaskbarView taskbarView) {
mControllerCallbacks = callbacks;
mTaskbarView = taskbarView;
}
@@ -0,0 +1,56 @@
/*
* 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;
import android.graphics.drawable.Drawable;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DragView;
/**
* A DragView drawn/used by the Taskbar. Note that this is only for the internal drag-and-drop,
* while the pre-drag is still in progress (i.e. when the long press popup is still open). After
* that ends, we switch to a system drag and drop view instead.
*/
public class TaskbarDragView extends DragView<TaskbarActivityContext> {
public TaskbarDragView(TaskbarActivityContext launcher, Drawable drawable, int registrationX,
int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) {
super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop,
finalScaleDps);
}
@Override
public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
Runnable onAnimationEnd = () -> {
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
mActivity.getDragLayer().removeView(this);
};
duration = Math.max(duration,
getResources().getInteger(R.integer.config_dropAnimMinDuration));
animate()
.translationX(toTouchX - mRegistrationX)
.translationY(toTouchY - mRegistrationY)
.scaleX(mScaleOnDrop)
.scaleY(mScaleOnDrop)
.withEndAction(onAnimationEnd)
.setDuration(duration)
.start();
}
}
@@ -62,10 +62,11 @@ public class TaskbarIconController {
ButtonProvider buttonProvider = new ButtonProvider(mActivity);
mImeBarView.init(buttonProvider);
mTaskbarView.construct(clickListener, longClickListener, buttonProvider);
mTaskbarView.init(new TaskbarViewCallbacks(), clickListener, longClickListener,
buttonProvider);
mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
mDragLayer.init(new Callbacks(), mTaskbarView);
mDragLayer.init(new TaskbarDragLayerCallbacks(), mTaskbarView);
}
public void onDestroy() {
@@ -102,7 +103,7 @@ public class TaskbarIconController {
/**
* Callbacks for {@link TaskbarDragLayer} to interact with the icon controller
*/
public class Callbacks {
public class TaskbarDragLayerCallbacks {
/**
* Called to update the touchable insets
@@ -160,4 +161,16 @@ public class TaskbarIconController {
mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE);
}
}
/**
* Callbacks for {@link TaskbarView} to interact with the icon controller
*/
public class TaskbarViewCallbacks {
/**
* Returns whether no other controller is currently handling the given View's visibility.
*/
public boolean canUpdateViewVisibility(View child) {
return !mActivity.getDragController().isDraggingView(child);
}
}
}
@@ -24,7 +24,6 @@ import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -35,7 +34,6 @@ import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -62,7 +60,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
private final TaskbarActivityContext mActivityContext;
// Initialized in TaskbarController constructor.
// Initialized in init.
private TaskbarIconController.TaskbarViewCallbacks mControllerCallbacks;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
@@ -75,7 +74,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
// Prevents dispatching touches to children if true
private boolean mTouchEnabled = true;
private boolean mIsDraggingItem;
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
@@ -118,8 +116,10 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
mHotseatIconsContainer = findViewById(R.id.hotseat_icons_layout);
}
protected void construct(OnClickListener clickListener, OnLongClickListener longClickListener,
ButtonProvider buttonProvider) {
protected void init(TaskbarIconController.TaskbarViewCallbacks callbacks,
OnClickListener clickListener, OnLongClickListener longClickListener,
ButtonProvider buttonProvider) {
mControllerCallbacks = callbacks;
mIconClickListener = clickListener;
mIconLongClickListener = longClickListener;
mButtonProvider = buttonProvider;
@@ -225,6 +225,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
}
private void updateHotseatItemVisibility(View hotseatView) {
if (!mControllerCallbacks.canUpdateViewVisibility(hotseatView)) {
return;
}
hotseatView.setVisibility(
hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE));
}
@@ -349,24 +352,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams);
}
@Override
public boolean onDragEvent(DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
mIsDraggingItem = true;
AbstractFloatingView.closeAllOpenViews(mActivityContext);
return true;
case DragEvent.ACTION_DRAG_ENDED:
mIsDraggingItem = false;
break;
}
return super.onDragEvent(event);
}
public boolean isDraggingItem() {
return mIsDraggingItem;
}
/**
* @return The bounding box of where the hotseat elements are relative to this TaskbarView.
*/
@@ -403,7 +403,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
}
}
void clearPressedBackground() {
public void clearPressedBackground() {
setPressed(false);
setStayPressed(false);
}
@@ -849,8 +849,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
switch (display) {
case DISPLAY_ALL_APPS:
return grid.allAppsIconSizePx;
case DISPLAY_WORKSPACE:
case DISPLAY_FOLDER:
return grid.folderChildIconSizePx;
case DISPLAY_WORKSPACE:
default:
return grid.iconSizePx;
}
+2 -1
View File
@@ -1289,7 +1289,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
}
}
public FolderIcon findFolderIcon(final int folderIconId) {
@Override
public @Nullable FolderIcon findFolderIcon(final int folderIconId) {
return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId);
}
+16 -14
View File
@@ -85,6 +85,7 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -651,25 +652,26 @@ public final class Utilities {
* @param outObj this is set to the internal data associated with {@param info},
* eg {@link LauncherActivityInfo} or {@link ShortcutInfo}.
*/
public static Drawable getFullDrawable(Launcher launcher, ItemInfo info, int width, int height,
public static Drawable getFullDrawable(Context context, ItemInfo info, int width, int height,
Object[] outObj) {
Drawable icon = loadFullDrawableWithoutTheme(launcher, info, width, height, outObj);
Drawable icon = loadFullDrawableWithoutTheme(context, info, width, height, outObj);
if (icon instanceof BitmapInfo.Extender) {
icon = ((BitmapInfo.Extender) icon).getThemedDrawable(launcher);
icon = ((BitmapInfo.Extender) icon).getThemedDrawable(context);
}
return icon;
}
private static Drawable loadFullDrawableWithoutTheme(Launcher launcher, ItemInfo info,
private static Drawable loadFullDrawableWithoutTheme(Context context, ItemInfo info,
int width, int height, Object[] outObj) {
LauncherAppState appState = LauncherAppState.getInstance(launcher);
ActivityContext activity = ActivityContext.lookupContext(context);
LauncherAppState appState = LauncherAppState.getInstance(context);
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
LauncherActivityInfo activityInfo = launcher.getSystemService(LauncherApps.class)
LauncherActivityInfo activityInfo = context.getSystemService(LauncherApps.class)
.resolveActivity(info.getIntent(), info.user);
outObj[0] = activityInfo;
return activityInfo == null ? null : LauncherAppState.getInstance(launcher)
return activityInfo == null ? null : LauncherAppState.getInstance(context)
.getIconProvider().getIcon(
activityInfo, launcher.getDeviceProfile().inv.fillResIconDpi);
activityInfo, activity.getDeviceProfile().inv.fillResIconDpi);
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
if (info instanceof PendingAddShortcutInfo) {
ShortcutConfigActivityInfo activityInfo =
@@ -678,18 +680,18 @@ public final class Utilities {
return activityInfo.getFullResIcon(appState.getIconCache());
}
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
.buildRequest(launcher)
.buildRequest(context)
.query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {
outObj[0] = si.get(0);
return ShortcutCachingLogic.getIcon(launcher, si.get(0),
return ShortcutCachingLogic.getIcon(context, si.get(0),
appState.getInvariantDeviceProfile().fillResIconDpi);
}
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
FolderAdaptiveIcon icon = FolderAdaptiveIcon.createFolderAdaptiveIcon(
launcher, info.id, new Point(width, height));
activity, info.id, new Point(width, height));
if (icon == null) {
return null;
}
@@ -707,8 +709,8 @@ public final class Utilities {
* badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge
**/
@TargetApi(Build.VERSION_CODES.O)
public static Drawable getBadge(Launcher launcher, ItemInfo info, Object obj) {
LauncherAppState appState = LauncherAppState.getInstance(launcher);
public static Drawable getBadge(Context context, ItemInfo info, Object obj) {
LauncherAppState appState = LauncherAppState.getInstance(context);
int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
boolean iconBadged = (info instanceof ItemInfoWithIcon)
@@ -728,7 +730,7 @@ public final class Utilities {
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return ((FolderAdaptiveIcon) obj).getBadge();
} else {
return launcher.getPackageManager()
return context.getPackageManager()
.getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
}
}
@@ -74,7 +74,7 @@ public abstract class DragController<T extends ActivityContext>
/** Coordinate for last touch event **/
protected final Point mLastTouch = new Point();
private final Point mTmpPoint = new Point();
protected final Point mTmpPoint = new Point();
protected DropTarget.DragObject mDragObject;
@@ -317,7 +317,7 @@ public abstract class DragController<T extends ActivityContext>
mDragObject.dragView.animateTo(mMotionDown.x, mMotionDown.y, onCompleteRunnable, duration);
}
private void callOnDragEnd() {
protected void callOnDragEnd() {
if (mIsInPreDrag && mOptions.preDragCondition != null) {
mOptions.preDragCondition.onPreDragEnd(mDragObject, false /* dragStarted*/);
}
@@ -343,7 +343,7 @@ public abstract class DragController<T extends ActivityContext>
/**
* Clamps the position to the drag layer bounds.
*/
private Point getClampedDragLayerPos(float x, float y) {
protected Point getClampedDragLayerPos(float x, float y) {
mActivity.getDragLayer().getLocalVisibleRect(mRectTemp);
mTmpPoint.x = (int) Math.max(mRectTemp.left, Math.min(x, mRectTemp.right - 1));
mTmpPoint.y = (int) Math.max(mRectTemp.top, Math.min(y, mRectTemp.bottom - 1));
@@ -390,7 +390,7 @@ public abstract class DragController<T extends ActivityContext>
return false;
}
Point dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
Point dragLayerPos = getClampedDragLayerPos(getX(ev), getY(ev));
mLastTouch.set(dragLayerPos.x, dragLayerPos.y);
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// Remember location of down touch
@@ -403,6 +403,14 @@ public abstract class DragController<T extends ActivityContext>
return mDragDriver != null && mDragDriver.onInterceptTouchEvent(ev);
}
protected float getX(MotionEvent ev) {
return ev.getX();
}
protected float getY(MotionEvent ev) {
return ev.getY();
}
/**
* Call this from a drag source view.
*/
@@ -165,8 +165,11 @@ public abstract class DragDriver {
* Class for driving an internal (i.e. not using framework) drag/drop operation.
*/
static class InternalDragDriver extends DragDriver {
private final DragController mDragController;
InternalDragDriver(DragController dragController, Consumer<MotionEvent> sec) {
super(dragController, sec);
mDragController = dragController;
}
@Override
@@ -176,11 +179,14 @@ public abstract class DragDriver {
switch (action) {
case MotionEvent.ACTION_MOVE:
mEventListener.onDriverDragMove(ev.getX(), ev.getY());
mEventListener.onDriverDragMove(mDragController.getX(ev),
mDragController.getY(ev));
break;
case MotionEvent.ACTION_UP:
mEventListener.onDriverDragMove(ev.getX(), ev.getY());
mEventListener.onDriverDragEnd(ev.getX(), ev.getY());
mEventListener.onDriverDragMove(mDragController.getX(ev),
mDragController.getY(ev));
mEventListener.onDriverDragEnd(mDragController.getX(ev),
mDragController.getY(ev));
break;
case MotionEvent.ACTION_CANCEL:
mEventListener.onDriverDragCancel();
@@ -197,7 +203,8 @@ public abstract class DragDriver {
switch (action) {
case MotionEvent.ACTION_UP:
mEventListener.onDriverDragEnd(ev.getX(), ev.getY());
mEventListener.onDriverDragEnd(mDragController.getX(ev),
mDragController.getY(ev));
break;
case MotionEvent.ACTION_CANCEL:
mEventListener.onDriverDragCancel();
@@ -53,22 +53,19 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
/** A custom view for rendering an icon, folder, shortcut or widget during drag-n-drop. */
public class DragView extends FrameLayout implements StateListener<LauncherState> {
public abstract class DragView<T extends Context & ActivityContext> extends FrameLayout {
public static final int VIEW_ZOOM_DURATION = 150;
@@ -81,19 +78,18 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
private final int mHeight;
private final int mBlurSizeOutline;
private final int mRegistrationX;
private final int mRegistrationY;
protected final int mRegistrationX;
protected final int mRegistrationY;
private final float mInitialScale;
private final float mScaleOnDrop;
private final int[] mTempLoc = new int[2];
protected final float mScaleOnDrop;
protected final int[] mTempLoc = new int[2];
private final RunnableList mOnDragStartCallback = new RunnableList();
private Point mDragVisualizeOffset = null;
private Rect mDragRegion = null;
private final Launcher mLauncher;
private final DragLayer mDragLayer;
@Thunk final DragController mDragController;
protected final T mActivity;
private final BaseDragLayer<T> mDragLayer;
private boolean mHasDrawn = false;
final ValueAnimator mAnim;
@@ -109,7 +105,7 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
private Path mScaledMaskPath;
private Drawable mBadge;
public DragView(Launcher launcher, Drawable drawable, int registrationX,
public DragView(T launcher, Drawable drawable, int registrationX,
int registrationY, final float initialScale, final float scaleOnDrop,
final float finalScaleDps) {
this(launcher, getViewFromDrawable(launcher, drawable),
@@ -122,7 +118,7 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
* <p>
* The registration point is the point inside our view that the touch events should
* be centered upon.
* @param launcher The Launcher instance
* @param activity The Launcher instance/ActivityContext this DragView is in.
* @param content the view content that is attached to the drag view.
* @param width the width of the dragView
* @param height the height of the dragView
@@ -132,13 +128,12 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
* @param scaleOnDrop the scale used in the drop animation.
* @param finalScaleDps the scale used in the zoom out animation when the drag view is shown.
*/
public DragView(Launcher launcher, View content, int width, int height, int registrationX,
public DragView(T activity, View content, int width, int height, int registrationX,
int registrationY, final float initialScale, final float scaleOnDrop,
final float finalScaleDps) {
super(launcher);
mLauncher = launcher;
mDragLayer = launcher.getDragLayer();
mDragController = launcher.getDragController();
super(activity);
mActivity = activity;
mDragLayer = activity.getDragLayer();
mContent = content;
mWidth = width;
@@ -187,24 +182,6 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
setWillNotDraw(false);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mLauncher.getStateManager().addStateListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mLauncher.getStateManager().removeStateListener(this);
}
@Override
public void onStateTransitionComplete(LauncherState finalState) {
setVisibility((finalState == LauncherState.NORMAL
|| finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
}
/**
* Initialize {@code #mIconDrawable} if the item can be represented using
* an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
@@ -221,10 +198,10 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
Object[] outObj = new Object[1];
int w = mWidth;
int h = mHeight;
Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h, outObj);
Drawable dr = Utilities.getFullDrawable(mActivity, info, w, h, outObj);
if (dr instanceof AdaptiveIconDrawable) {
int blurMargin = (int) mLauncher.getResources()
int blurMargin = (int) mActivity.getResources()
.getDimension(R.dimen.blur_size_medium_outline) / 2;
Rect bounds = new Rect(0, 0, w, h);
@@ -232,13 +209,13 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
// Badge is applied after icon normalization so the bounds for badge should not
// be scaled down due to icon normalization.
Rect badgeBounds = new Rect(bounds);
mBadge = getBadge(mLauncher, info, outObj[0]);
mBadge = getBadge(mActivity, info, outObj[0]);
mBadge.setBounds(badgeBounds);
// Do not draw the background in case of folder as its translucent
final boolean shouldDrawBackground = !(dr instanceof FolderAdaptiveIcon);
try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
try (LauncherIcons li = LauncherIcons.obtain(mActivity)) {
Drawable nDr; // drawable to be normalized
if (shouldDrawBackground) {
nDr = dr;
@@ -429,12 +406,11 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
applyTranslation();
}
public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
mTempLoc[0] = toTouchX - mRegistrationX;
mTempLoc[1] = toTouchY - mRegistrationY;
mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop, mScaleOnDrop,
DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
}
/**
* Animate this DragView to the given DragLayer coordinates and then remove it.
*/
public abstract void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable,
int duration);
public void animateShift(final int shiftX, final int shiftY) {
if (mAnim.isStarted()) {
@@ -470,7 +446,7 @@ public class DragView extends FrameLayout implements StateListener<LauncherState
Picture picture = new Picture();
mContent.draw(picture.beginRecording(mWidth, mHeight));
picture.endRecording();
View view = new View(mLauncher);
View view = new View(mActivity);
view.setClipToOutline(mContent.getClipToOutline());
view.setOutlineProvider(mContent.getOutlineProvider());
view.setBackground(new PictureDrawable(picture));
@@ -32,12 +32,12 @@ import android.util.Log;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.views.ActivityContext;
/**
* {@link AdaptiveIconDrawable} representation of a {@link FolderIcon}
@@ -70,14 +70,14 @@ public class FolderAdaptiveIcon extends AdaptiveIconDrawable {
}
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
Launcher launcher, int folderId, Point dragViewSize) {
ActivityContext activity, int folderId, Point dragViewSize) {
Preconditions.assertNonUiThread();
// Create the actual drawable on the UI thread to avoid race conditions with
// FolderIcon draw pass
try {
return MAIN_EXECUTOR.submit(() -> {
FolderIcon icon = launcher.findFolderIcon(folderId);
FolderIcon icon = activity.findFolderIcon(folderId);
return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize);
}).get();
@@ -96,7 +96,7 @@ public class LauncherDragController extends DragController<Launcher> {
final float scaleDps = mIsInPreDrag
? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
final DragView dragView = mDragObject.dragView = drawable != null
? new DragView(
? new LauncherDragView(
mActivity,
drawable,
registrationX,
@@ -104,7 +104,7 @@ public class LauncherDragController extends DragController<Launcher> {
initialDragViewScale,
dragViewScaleOnDrop,
scaleDps)
: new DragView(
: new LauncherDragView(
mActivity,
view,
view.getMeasuredWidth(),
@@ -0,0 +1,70 @@
/*
* 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.dragndrop;
import android.graphics.drawable.Drawable;
import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StateManager;
/**
* A DragView drawn/used by the Launcher activity.
*/
public class LauncherDragView extends DragView<Launcher>
implements StateManager.StateListener<LauncherState> {
public LauncherDragView(Launcher launcher, Drawable drawable, int registrationX,
int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) {
super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop,
finalScaleDps);
}
public LauncherDragView(Launcher launcher, View content, int width, int height,
int registrationX, int registrationY, float initialScale, float scaleOnDrop,
float finalScaleDps) {
super(launcher, content, width, height, registrationX, registrationY, initialScale,
scaleOnDrop, finalScaleDps);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mActivity.getStateManager().addStateListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mActivity.getStateManager().removeStateListener(this);
}
@Override
public void onStateTransitionComplete(LauncherState finalState) {
setVisibility((finalState == LauncherState.NORMAL
|| finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
}
@Override
public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
mTempLoc[0] = toTouchX - mRegistrationX;
mTempLoc[1] = toTouchY - mRegistrationY;
mActivity.getDragLayer().animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop,
mScaleOnDrop, DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
}
}
@@ -32,13 +32,13 @@ import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import java.nio.ByteBuffer;
@@ -150,7 +150,7 @@ public class DragPreviewProvider {
}
public float getScaleAndPosition(Drawable preview, int[] outPos) {
float scale = Launcher.getLauncher(mView.getContext())
float scale = ActivityContext.lookupContext(mView.getContext())
.getDragLayer().getLocationInDragLayer(mView, outPos);
if (mView instanceof LauncherAppWidgetHostView) {
// App widgets are technically scaled, but are drawn at their expected size -- so the
@@ -167,7 +167,7 @@ public class DragPreviewProvider {
/** Returns the scale and position of a given view for drag-n-drop. */
public float getScaleAndPosition(View view, int[] outPos) {
float scale = Launcher.getLauncher(mView.getContext())
float scale = ActivityContext.lookupContext(mView.getContext())
.getDragLayer().getLocationInDragLayer(mView, outPos);
if (mView instanceof LauncherAppWidgetHostView) {
// App widgets are technically scaled, but are drawn at their expected size -- so the
@@ -201,7 +201,7 @@ public class DragPreviewProvider {
public void run() {
Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot);
if (mIsIcon) {
int size = Launcher.getLauncher(mContext).getDeviceProfile().iconSizePx;
int size = ActivityContext.lookupContext(mContext).getDeviceProfile().iconSizePx;
preview = Bitmap.createScaledBitmap(preview, size, size, false);
}
//else case covers AppWidgetHost (doesn't drag/drop across different device profiles)
@@ -21,9 +21,12 @@ import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View.AccessibilityDelegate;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ViewCache;
@@ -99,6 +102,13 @@ public interface ActivityContext {
return null;
}
/**
* Returns the FolderIcon with the given item id, if it exists.
*/
default @Nullable FolderIcon findFolderIcon(final int folderIconId) {
return null;
}
/**
* Returns the ActivityContext associated with the given Context.
*/