Snap for 7236705 from 0a74a35a41 to sc-v2-release

Change-Id: Ic8607f7b47f5e8c84474793cecf2fd31b83b569b
This commit is contained in:
android-build-team Robot
2021-03-26 01:07:55 +00:00
76 changed files with 965 additions and 778 deletions
+2
View File
@@ -0,0 +1,2 @@
rajekumar@google.com
spivack@google.com
+1 -1
View File
@@ -10,5 +10,5 @@
<!-- Label for a button that translates a screenshot of the current app. [CHAR_LIMIT=40] -->
<string name="action_translate">Translate</string>
<!-- Label for a button that triggers Search on a screenshot of the current app. [CHAR_LIMIT=40] -->
<string name="action_search">Search</string>
<string name="action_search">Lens</string>
</resources>
@@ -36,6 +36,8 @@ import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskThumbnailView;
@@ -51,6 +53,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH";
public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos";
public static final String ACTIONS_URL = "niu_actions_app_url";
private static final String ASSIST_KEY_CONTENT = "content";
private static final String TAG = "TaskOverlayFactoryGo";
// Empty constructor required for ResourceBasedOverride
@@ -68,8 +71,6 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
* @param <T> The type of View in which the overlay will be placed
*/
public static final class TaskOverlayGo<T extends OverviewActionsView> extends TaskOverlay {
private static final String ASSIST_KEY_CONTENT = "content";
private String mNIUPackageName;
private int mTaskId;
private Bundle mAssistData;
@@ -95,7 +96,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
}
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
mTaskId = task.key.id;
@@ -122,7 +123,11 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
});
}
private void sendNIUIntent(String actionType) {
/**
* Creates and sends an Intent corresponding to the button that was clicked
*/
@VisibleForTesting
public void sendNIUIntent(String actionType) {
Intent intent = createNIUIntent(actionType);
mImageApi.shareAsDataWithExplicitIntent(/* crop */ null, intent);
}
@@ -178,6 +183,11 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
}
}
}
@VisibleForTesting
public void setImageActionsAPI(ImageActionsApi imageActionsApi) {
mImageApi = imageActionsApi;
}
}
/**
@@ -22,5 +22,4 @@
android:layout_height="wrap_content"
android:text="@string/recents_clear_all"
android:textColor="?attr/workspaceTextColor"
android:textSize="14sp"
android:translationY="@dimen/task_thumbnail_half_top_margin" />
android:textSize="14sp" />
+3 -2
View File
@@ -13,6 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- NOTE! don't add dimensions for margins / paddings / sizes that change per orientation to this
file, they need to be loaded at runtime. -->
<com.android.quickstep.views.TaskView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -24,8 +26,7 @@
<com.android.quickstep.views.TaskThumbnailView
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/task_thumbnail_top_margin"/>
android:layout_height="match_parent"/>
<com.android.quickstep.views.IconView
android:id="@+id/icon"
+2
View File
@@ -16,4 +16,6 @@
-->
<resources>
<dimen name="task_card_menu_horizontal_padding">24dp</dimen>
<dimen name="overview_task_margin">8dp</dimen>
</resources>
+1 -4
View File
@@ -15,11 +15,8 @@
-->
<resources>
<dimen name="task_thumbnail_top_margin">80dp</dimen>
<dimen name="task_thumbnail_half_top_margin">40dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<dimen name="task_icon_top_margin">16dp</dimen>
<dimen name="task_thumbnail_icon_size_grid">32dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
@@ -335,13 +335,17 @@ public abstract class BaseQuickstepLauncher extends Launcher
? new float[] {1, 1} : new float[] {1.1f, 0};
}
@Override
public float getNormalTaskbarScale() {
if (mTaskbarController != null) {
return mTaskbarController.getTaskbarScaleOnHome();
}
return super.getNormalTaskbarScale();
}
@Override
public void onDragLayerHierarchyChanged() {
onLauncherStateOrFocusChanged();
if (mTaskbarController != null) {
mTaskbarController.onLauncherDragLayerHierarchyChanged();
}
}
@Override
@@ -35,14 +35,13 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo
private final DeviceProfile mDeviceProfile;
private final LayoutInflater mLayoutInflater;
private final TaskbarContainerView mTaskbarContainerView;
private final float mIconScale;
public TaskbarActivityContext(BaseQuickstepLauncher launcher) {
super(launcher);
mDeviceProfile = launcher.getDeviceProfile().copy(this);
float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
mIconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
mDeviceProfile.updateIconSize(mIconScale, getResources());
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
mDeviceProfile.updateIconSize(iconScale, getResources());
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
@@ -73,11 +72,4 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo
public Rect getFolderBoundingBox() {
return mTaskbarContainerView.getFolderBoundingBox();
}
/**
* @return The ratio of taskbar icon size vs normal workspace/hotseat icon size.
*/
public float getTaskbarIconScale() {
return mIconScale;
}
}
@@ -20,36 +20,38 @@ import static com.android.launcher3.LauncherState.TASKBAR;
import android.animation.Animator;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.Utilities;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
/**
* Works with TaskbarController to update the TaskbarView's alpha based on LauncherState, whether
* Launcher is in the foreground, etc.
* Works with TaskbarController to update the TaskbarView's visual properties based on factors such
* as LauncherState, whether Launcher is in the foreground, etc.
*/
public class TaskbarVisibilityController {
public class TaskbarAnimationController {
private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
private static final long FLOATING_VIEW_VISIBILITY_ALPHA_DURATION = 120;
private final BaseQuickstepLauncher mLauncher;
private final TaskbarController.TaskbarVisibilityControllerCallbacks mTaskbarCallbacks;
private final TaskbarController.TaskbarAnimationControllerCallbacks mTaskbarCallbacks;
// Background alpha.
private AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
this::onTaskbarBackgroundAlphaChanged);
// Overall visibility.
private AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
this::updateVisibilityAlpha);
private AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
this::updateVisibilityAlpha);
private AnimatedFloat mTaskbarVisibilityAlphaForFloatingView = new AnimatedFloat(
private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
this::updateVisibilityAlpha);
public TaskbarVisibilityController(BaseQuickstepLauncher launcher,
TaskbarController.TaskbarVisibilityControllerCallbacks taskbarCallbacks) {
// Scale.
private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat(
this::updateScale);
public TaskbarAnimationController(BaseQuickstepLauncher launcher,
TaskbarController.TaskbarAnimationControllerCallbacks taskbarCallbacks) {
mLauncher = launcher;
mTaskbarCallbacks = taskbarCallbacks;
}
@@ -62,7 +64,6 @@ public class TaskbarVisibilityController {
boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
& QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
mTaskbarVisibilityAlphaForFloatingView.updateValue(1f);
onTaskbarBackgroundAlphaChanged();
updateVisibilityAlpha();
@@ -76,6 +77,10 @@ public class TaskbarVisibilityController {
return mTaskbarVisibilityAlphaForLauncherState;
}
protected AnimatedFloat getTaskbarScaleForLauncherState() {
return mTaskbarScaleForLauncherState;
}
protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
.setDuration(duration);
@@ -86,14 +91,10 @@ public class TaskbarVisibilityController {
.setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
}
protected void animateToVisibilityForFloatingView(float toAlpha) {
mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForFloatingView.value,
toAlpha).setDuration(FLOATING_VIEW_VISIBILITY_ALPHA_DURATION).start();
}
private void onTaskbarBackgroundAlphaChanged() {
mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
updateVisibilityAlpha();
updateScale();
}
private void updateVisibilityAlpha() {
@@ -102,8 +103,7 @@ public class TaskbarVisibilityController {
// LauncherState if Launcher is paused.
float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
mTaskbarVisibilityAlphaForLauncherState.value);
float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value
* mTaskbarVisibilityAlphaForFloatingView.value;
float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value;
float taskbarAlpha = alphaDueToLauncher * alphaDueToOther;
mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha);
@@ -111,6 +111,15 @@ public class TaskbarVisibilityController {
setNavBarButtonAlpha(1f - taskbarAlpha);
}
private void updateScale() {
// We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
// assumption being that Taskbar should always be at scale 1f regardless of the current
// LauncherState if Launcher is paused.
float scale = mTaskbarScaleForLauncherState.value;
scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f);
mTaskbarCallbacks.updateTaskbarScale(scale);
}
private void setNavBarButtonAlpha(float navBarAlpha) {
SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false);
}
@@ -19,8 +19,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -75,7 +73,7 @@ public class TaskbarController {
// Layout width and height of the Taskbar in the default state.
private final Point mTaskbarSize;
private final TaskbarStateHandler mTaskbarStateHandler;
private final TaskbarVisibilityController mTaskbarVisibilityController;
private final TaskbarAnimationController mTaskbarAnimationController;
private final TaskbarHotseatController mHotseatController;
private final TaskbarRecentsController mRecentsController;
private final TaskbarDragController mDragController;
@@ -104,8 +102,8 @@ public class TaskbarController {
mWindowManager = mLauncher.getWindowManager();
mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize);
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
mTaskbarVisibilityController = new TaskbarVisibilityController(mLauncher,
createTaskbarVisibilityControllerCallbacks());
mTaskbarAnimationController = new TaskbarAnimationController(mLauncher,
createTaskbarAnimationControllerCallbacks());
mHotseatController = new TaskbarHotseatController(mLauncher,
createTaskbarHotseatControllerCallbacks());
mRecentsController = new TaskbarRecentsController(mLauncher,
@@ -113,8 +111,8 @@ public class TaskbarController {
mDragController = new TaskbarDragController(mLauncher);
}
private TaskbarVisibilityControllerCallbacks createTaskbarVisibilityControllerCallbacks() {
return new TaskbarVisibilityControllerCallbacks() {
private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
return new TaskbarAnimationControllerCallbacks() {
@Override
public void updateTaskbarBackgroundAlpha(float alpha) {
mTaskbarViewInApp.setBackgroundAlpha(alpha);
@@ -125,6 +123,12 @@ public class TaskbarController {
mTaskbarContainerView.setAlpha(alpha);
mTaskbarViewOnHome.setAlpha(alpha);
}
@Override
public void updateTaskbarScale(float scale) {
mTaskbarViewInApp.setScaleX(scale);
mTaskbarViewInApp.setScaleY(scale);
}
};
}
@@ -151,13 +155,22 @@ public class TaskbarController {
ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
ActivityOptions.makeBasic());
} else if (tag instanceof FolderInfo) {
if (mLauncher.hasBeenResumed()) {
FolderInfo folderInfo = (FolderInfo) tag;
onClickedOnFolderFromHome(folderInfo);
} else {
FolderIcon folderIcon = (FolderIcon) view;
onClickedOnFolderInApp(folderIcon);
}
FolderIcon folderIcon = (FolderIcon) view;
Folder folder = folderIcon.getFolder();
setTaskbarWindowFullscreen(true);
mTaskbarContainerView.post(() -> {
folder.animateOpen();
folder.iterateOverItems((itemInfo, itemView) -> {
itemView.setOnClickListener(getItemOnClickListener());
itemView.setOnLongClickListener(getItemOnLongClickListener());
// To play haptic when dragging, like other Taskbar items do.
itemView.setHapticFeedbackEnabled(true);
return false;
});
});
} else {
ItemClickHandler.INSTANCE.onClick(view);
}
@@ -167,44 +180,9 @@ public class TaskbarController {
};
}
// Open the real folder in Launcher.
private void onClickedOnFolderFromHome(FolderInfo folderInfo) {
alignRealHotseatWithTaskbar();
FolderIcon folderIcon = (FolderIcon) mLauncher.getHotseat()
.getFirstItemMatch((info, v) -> info == folderInfo);
folderIcon.post(folderIcon::performClick);
}
// Open the Taskbar folder, and handle clicks on folder items.
private void onClickedOnFolderInApp(FolderIcon folderIcon) {
Folder folder = folderIcon.getFolder();
setTaskbarWindowFullscreen(true);
mTaskbarContainerView.post(() -> {
folder.animateOpen();
folder.iterateOverItems((itemInfo, itemView) -> {
itemView.setOnClickListener(getItemOnClickListener());
itemView.setOnLongClickListener(getItemOnLongClickListener());
// To play haptic when dragging, like other Taskbar items do.
itemView.setHapticFeedbackEnabled(true);
return false;
});
});
}
@Override
public View.OnLongClickListener getItemOnLongClickListener() {
return view -> {
if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
// TODO: remove this path
return mDragController.startWorkspaceDragOnLongClick(view);
} else {
return mDragController.startSystemDragOnLongClick(view);
}
};
return mDragController::startSystemDragOnLongClick;
}
@Override
@@ -268,12 +246,10 @@ public class TaskbarController {
mTaskbarContainerView.init(mTaskbarViewInApp);
addToWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
mTaskbarVisibilityController.init();
mTaskbarAnimationController.init();
mHotseatController.init();
mRecentsController.init();
SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed()
? getTaskbarScaleOnHome() : 1f);
updateWhichTaskbarViewIsVisible();
}
@@ -281,7 +257,12 @@ public class TaskbarController {
return new TaskbarStateHandlerCallbacks() {
@Override
public AnimatedFloat getAlphaTarget() {
return mTaskbarVisibilityController.getTaskbarVisibilityForLauncherState();
return mTaskbarAnimationController.getTaskbarVisibilityForLauncherState();
}
@Override
public AnimatedFloat getScaleTarget() {
return mTaskbarAnimationController.getTaskbarScaleForLauncherState();
}
};
}
@@ -300,7 +281,7 @@ public class TaskbarController {
mTaskbarContainerView.cleanup();
removeFromWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(null);
mTaskbarVisibilityController.cleanup();
mTaskbarAnimationController.cleanup();
mHotseatController.cleanup();
mRecentsController.cleanup();
}
@@ -368,12 +349,10 @@ public class TaskbarController {
*/
public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
PendingAnimation anim = new PendingAnimation(duration);
anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(0, duration));
anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration));
if (toState != null) {
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
}
anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(),
getTaskbarScaleOnHome(), LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -394,8 +373,7 @@ public class TaskbarController {
private Animator createAnimToApp(long duration) {
PendingAnimation anim = new PendingAnimation(duration);
anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration));
anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR);
anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration));
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -416,7 +394,7 @@ public class TaskbarController {
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
*/
public void setIsImeVisible(boolean isImeVisible) {
mTaskbarVisibilityController.animateToVisibilityForIme(isImeVisible ? 0 : 1);
mTaskbarAnimationController.animateToVisibilityForIme(isImeVisible ? 0 : 1);
}
/**
@@ -509,14 +487,6 @@ public class TaskbarController {
mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
}
/**
* A view was added or removed from DragLayer, check if we need to hide our hotseat copy and
* show the real one instead.
*/
public void onLauncherDragLayerHierarchyChanged() {
// TODO: remove, as this is a no-op now
}
private void updateWhichTaskbarViewIsVisible() {
boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
|| mIsAnimatingToApp;
@@ -561,15 +531,17 @@ public class TaskbarController {
*/
protected interface TaskbarStateHandlerCallbacks {
AnimatedFloat getAlphaTarget();
AnimatedFloat getScaleTarget();
}
/**
* Contains methods that TaskbarVisibilityController can call to interface with
* Contains methods that TaskbarAnimationController can call to interface with
* TaskbarController.
*/
protected interface TaskbarVisibilityControllerCallbacks {
protected interface TaskbarAnimationControllerCallbacks {
void updateTaskbarBackgroundAlpha(float alpha);
void updateTaskbarVisibilityAlpha(float alpha);
void updateTaskbarScale(float scale);
}
/**
@@ -33,7 +33,6 @@ import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
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;
@@ -125,38 +124,6 @@ public class TaskbarDragController {
return false;
}
/**
* Starts a drag and drop operation that controls a real Workspace (Hotseat) view.
* @param view The Taskbar item that was long clicked.
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
protected boolean startWorkspaceDragOnLongClick(View view) {
View.DragShadowBuilder transparentShadowBuilder = new View.DragShadowBuilder(view) {
private static final int ARBITRARY_SHADOW_SIZE = 10;
@Override
public void onDrawShadow(Canvas canvas) {
}
@Override
public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
outShadowSize.set(ARBITRARY_SHADOW_SIZE, ARBITRARY_SHADOW_SIZE);
outShadowTouchPoint.set(ARBITRARY_SHADOW_SIZE / 2, ARBITRARY_SHADOW_SIZE / 2);
}
};
TaskbarDragListener taskbarDragListener = new TaskbarDragListener(mLauncher,
(ItemInfo) view.getTag());
if (view.startDragAndDrop(new ClipData("", new String[] {taskbarDragListener.getMimeType()},
new ClipData.Item("")),
transparentShadowBuilder, null /* localState */, View.DRAG_FLAG_GLOBAL)) {
view.setOnDragListener(getDraggedViewDragListener());
taskbarDragListener.init(mLauncher.getDragLayer());
return true;
}
return false;
}
/**
* Hide the original Taskbar item while it is being dragged.
*/
@@ -1,101 +0,0 @@
/*
* 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.content.ClipDescription;
import android.graphics.Point;
import android.view.DragEvent;
import android.view.View;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.model.data.ItemInfo;
import java.util.UUID;
/**
* Listens to system drag and drop events initated by the Taskbar, and forwards them to Launcher's
* internal DragController to move Hotseat items.
*/
public class TaskbarDragListener implements View.OnDragListener {
private static final String MIME_TYPE_PREFIX = "com.android.launcher3.taskbar.drag_and_drop/";
private final BaseQuickstepLauncher mLauncher;
private final ItemInfo mDraggedItem;
// Randomly generated id used to verify the drag event.
private final String mId;
// Initialized in init().
DragLayer mDragLayer;
/**
* @param draggedItem The info of the item that was long clicked, which we will use to find
* the equivalent match on Hotseat to drag internally.
*/
public TaskbarDragListener(BaseQuickstepLauncher launcher, ItemInfo draggedItem) {
mLauncher = launcher;
mDraggedItem = draggedItem;
mId = UUID.randomUUID().toString();
}
protected void init(DragLayer dragLayer) {
mDragLayer = dragLayer;
mDragLayer.setOnDragListener(this);
// Temporarily disable haptics, as system will already play one when drag and drop starts.
mDragLayer.setHapticFeedbackEnabled(false);
}
private void cleanup() {
mDragLayer.setOnDragListener(null);
mLauncher.setNextWorkspaceDragOptions(null);
mDragLayer.setHapticFeedbackEnabled(true);
}
/**
* Returns a randomly generated id used to verify the drag event.
*/
protected String getMimeType() {
return MIME_TYPE_PREFIX + mId;
}
@Override
public boolean onDrag(View dragLayer, DragEvent dragEvent) {
ClipDescription clipDescription = dragEvent.getClipDescription();
if (dragEvent.getAction() == DragEvent.ACTION_DRAG_STARTED) {
if (clipDescription == null || !clipDescription.hasMimeType(getMimeType())) {
// We didn't initiate this drag, ignore.
cleanup();
return false;
}
View hotseatView = mLauncher.getHotseat().getFirstItemMatch(
(info, view) -> info == mDraggedItem);
if (hotseatView == null) {
cleanup();
return false;
}
DragOptions dragOptions = new DragOptions();
dragOptions.simulatedDndStartPoint = new Point((int) dragEvent.getX(),
(int) dragEvent.getY());
mLauncher.setNextWorkspaceDragOptions(dragOptions);
hotseatView.performLongClick();
} else if (dragEvent.getAction() == DragEvent.ACTION_DRAG_ENDED) {
cleanup();
}
return mLauncher.getDragController().onDragEvent(dragEvent);
}
}
@@ -16,14 +16,12 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherState.TASKBAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
@@ -55,8 +53,10 @@ public class TaskbarStateHandler implements StateManager.StateHandler<LauncherSt
}
AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget();
boolean isTaskbarVisible = (state.getVisibleElements(mLauncher) & TASKBAR) != 0;
alphaTarget.updateValue(isTaskbarVisible ? 1f : 0f);
scaleTarget.updateValue(state.getTaskbarScale(mLauncher));
}
@Override
@@ -65,13 +65,12 @@ public class TaskbarStateHandler implements StateManager.StateHandler<LauncherSt
if (mTaskbarCallbacks == null) {
return;
}
if (config.hasAnimationFlag(SKIP_TASKBAR)) {
return;
}
AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget();
boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f,
config.getInterpolator(ANIM_TASKBAR_FADE, Interpolators.LINEAR));
animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
animation.setFloat(scaleTarget, AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher),
LINEAR);
}
}
@@ -120,11 +120,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
}
protected void init(int numHotseatIcons, int numRecentIcons) {
mLayoutTransition = new LayoutTransition();
addUpdateListenerForAllLayoutTransitions(
() -> mControllerCallbacks.onItemPositionsChanged(this));
setLayoutTransition(mLayoutTransition);
mHotseatStartIndex = 0;
mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1;
updateHotseatItems(new ItemInfo[numHotseatIcons]);
@@ -135,6 +130,14 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
mRecentsStartIndex = dividerIndex + 1;
mRecentsEndIndex = mRecentsStartIndex + numRecentIcons - 1;
updateRecentTasks(new Task[numRecentIcons]);
mLayoutTransition = new LayoutTransition();
addUpdateListenerForAllLayoutTransitions(() -> {
if (getLayoutTransition() == mLayoutTransition) {
mControllerCallbacks.onItemPositionsChanged(this);
}
});
setLayoutTransition(mLayoutTransition);
}
private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) {
@@ -159,10 +162,20 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
}
protected void cleanup() {
endAllLayoutTransitionAnimators();
setLayoutTransition(null);
removeAllViews();
mHotseatRecentsDivider = null;
}
private void endAllLayoutTransitionAnimators() {
mLayoutTransition.getAnimator(LayoutTransition.CHANGE_APPEARING).end();
mLayoutTransition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING).end();
mLayoutTransition.getAnimator(LayoutTransition.CHANGING).end();
mLayoutTransition.getAnimator(LayoutTransition.APPEARING).end();
mLayoutTransition.getAnimator(LayoutTransition.DISAPPEARING).end();
}
/**
* Sets the alpha of the background color behind all the Taskbar contents.
* @param alpha 0 is fully transparent, 1 is fully opaque.
@@ -82,6 +82,11 @@ public class OverviewState extends LauncherState {
return new float[] {NO_SCALE, NO_OFFSET};
}
@Override
public float getTaskbarScale(Launcher launcher) {
return 1f;
}
@Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@@ -18,7 +18,6 @@ package com.android.launcher3.uioverrides.states;
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
@@ -33,12 +32,10 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
@@ -82,7 +79,6 @@ public class QuickstepAtomicAnimationFactory extends
if (toState == NORMAL && fromState == OVERVIEW) {
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
config.setInterpolator(ANIM_TASKBAR_FADE, ACCEL);
config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL);
@@ -141,7 +137,6 @@ public class QuickstepAtomicAnimationFactory extends
config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_2);
config.setInterpolator(ANIM_TASKBAR_FADE, OVERSHOOT_1_2);
} else if (fromState == HINT_STATE && toState == NORMAL) {
config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
if (mHintToNormalDuration == -1) {
@@ -150,17 +145,6 @@ public class QuickstepAtomicAnimationFactory extends
mHintToNormalDuration = (int) va.getDuration();
}
config.duration = Math.max(config.duration, mHintToNormalDuration);
} else if (mActivity.getTaskbarController() != null) {
boolean wasHotseatVisible = fromState.areElementsVisible(mActivity, HOTSEAT_ICONS);
boolean isHotseatVisible = toState.areElementsVisible(mActivity, HOTSEAT_ICONS);
if (wasHotseatVisible || isHotseatVisible) {
config.setInterpolator(ANIM_TASKBAR_FADE, INSTANT);
config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT);
if (isHotseatVisible) {
mActivity.getTaskbarController().alignRealHotseatWithTaskbar();
}
}
}
}
}
@@ -22,7 +22,6 @@ import static android.widget.Toast.LENGTH_SHORT;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -97,11 +96,12 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.InputProxyHandlerFactory;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.SwipePipToHomeAnimator;
import com.android.quickstep.util.TransformParams;
@@ -113,12 +113,10 @@ import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskInfoCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -200,7 +198,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public static final long MAX_SWIPE_DURATION = 350;
public static final long MIN_OVERSHOOT_DURATION = 120;
public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
private static final float SWIPE_DURATION_MULTIPLIER =
@@ -255,7 +253,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler);
new InputConsumerProxy(inputConsumer, () -> {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -783,19 +784,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
}
/**
* Called to create a input proxy for the running task
*/
@UiThread
protected InputConsumer createNewInputProxyHandler() {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
StatefulActivity activity = mActivityInterface.getCreatedActivity();
return activity == null ? InputConsumer.NO_OP
: new OverviewInputConsumer(mGestureState, activity, null, true);
}
private void endRunningWindowAnim(boolean cancel) {
if (mRunningWindowAnim != null) {
if (cancel) {
@@ -923,6 +911,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
float currentShift = mCurrentShift.value;
final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
isFling, isCancel);
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(endTarget, false /* isAtomic */);
float endShift = endTarget.isLauncher ? 1 : 0;
final float startShift;
if (!isFling) {
@@ -945,7 +936,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
Interpolator interpolator;
S state = mActivityInterface.stateFromGestureEndTarget(endTarget);
if (state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
if (state.displayOverviewTasksAsGrid(mDp)) {
interpolator = ACCEL_DEACCEL;
} else if (endTarget == RECENTS) {
interpolator = OVERSHOOT_1_2;
@@ -957,7 +948,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
duration = HOME_DURATION;
} else if (endTarget == RECENTS) {
if (mRecentsView != null) {
int nearestPage = mRecentsView.getDestinationPage();
@@ -1055,8 +1046,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
@UiThread
private void animateToProgressInternal(float start, float end, long duration,
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(target, false /* isAtomic */);
maybeUpdateRecentsAttachedState();
// If we are transitioning to launcher, then listen for the activity to be restarted while
@@ -1147,10 +1136,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
});
animatorSet.play(windowAnim);
S state = mActivityInterface.stateFromGestureEndTarget(mGestureState.getEndTarget());
if (mRecentsView != null && state.displayOverviewTasksAsGrid(
mActivity.getDeviceProfile())) {
if (mRecentsView != null && state.displayOverviewTasksAsGrid(mDp)) {
animatorSet.play(ObjectAnimator.ofFloat(mRecentsView, RECENTS_GRID_PROGRESS, 1));
animatorSet.play(mTaskViewSimulator.gridProgress.animateToValue(0, 1));
}
animatorSet.setDuration(duration).setInterpolator(interpolator);
animatorSet.start();
@@ -1339,6 +1326,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mInputConsumerProxy.destroy();
mTaskAnimationManager.setLiveTileCleanUpHandler(null);
}
mInputConsumerProxy.unregisterCallback();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
@@ -1503,36 +1491,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
protected abstract void finishRecentsControllerToHome(Runnable callback);
private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
if (mRecentsView.getRunningTaskIndex() != -1
&& mRecentsView.getRunningTaskId() == task.taskId
&& mRecentsAnimationTargets.hasTask(task.taskId)) {
launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps);
}
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
mLiveTileRestartListener);
}
};
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
mRecentsView.onSwipeUpAnimationSuccess();
if (LIVE_TILE.get()) {
mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
appearedTaskTarget -> {
RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
mRecentsAnimationTargets.apps,
mRecentsAnimationTargets.apps.length + 1);
apps[apps.length - 1] = appearedTaskTarget;
launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
});
mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
ActivityManagerWrapper.getInstance().registerTaskStackListener(
mLiveTileRestartListener);
mTaskAnimationManager.enableLiveTileRestartListener();
}
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
@@ -1540,65 +1505,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
reset();
}
private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
AnimatorSet anim = new AnimatorSet();
TaskView taskView = mRecentsView.getTaskView(taskId);
if (taskView == null || !mRecentsView.isTaskViewVisible(taskView)) {
// TODO: Refine this animation.
SurfaceTransactionApplier surfaceApplier =
new SurfaceTransactionApplier(mActivity.getDragLayer());
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
appAnimator.setInterpolator(ACCEL_DEACCEL);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@Override
public void onUpdate(float percent) {
SurfaceParams.Builder builder = new SurfaceParams.Builder(
apps[apps.length - 1].leash);
Matrix matrix = new Matrix();
matrix.postScale(percent, percent);
matrix.postTranslate(mDp.widthPx * (1 - percent) / 2,
mDp.heightPx * (1 - percent) / 2);
builder.withAlpha(percent).withMatrix(matrix);
surfaceApplier.scheduleApply(builder.build());
}
});
anim.play(appAnimator);
} else {
TaskViewUtils.composeRecentsLaunchAnimator(
anim, taskView, apps,
mRecentsAnimationTargets.wallpapers, true /* launcherClosing */,
mActivity.getStateManager(), mRecentsView,
mActivityInterface.getDepthController());
}
anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animator) {
cleanUp(false);
}
@Override
public void onAnimationCancel(Animator animator) {
cleanUp(true);
}
private void cleanUp(boolean canceled) {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
if (canceled) {
mRecentsAnimationController = null;
} else {
mActivityInterface.onLaunchTaskSuccess();
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
}
}
});
anim.start();
}
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == ACTIVITY_TYPE_HOME;
@@ -31,6 +31,7 @@ import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.view.Gravity;
@@ -43,6 +44,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -195,41 +197,53 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
}
/**
* Calculates the taskView size for the provided device configuration
* Calculates the taskView size for the provided device configuration.
*/
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
Resources res = context.getResources();
if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
Rect gridRect = new Rect();
calculateGridSize(context, dp, gridRect);
int taskMargin = res.getDimensionPixelSize(R.dimen.overview_task_margin);
int taskIconAndMargin = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size)
+ res.getDimensionPixelSize(R.dimen.task_icon_top_margin);
int proactiveRowAndMargin = res.getDimensionPixelSize(R.dimen.overview_proactive_row_height)
+ res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
float rowHeight = (gridRect.height() - rowSpacing) / 2f;
calculateTaskSizeInternal(context, dp,
taskIconAndMargin + taskMargin,
proactiveRowAndMargin + getOverviewActionsHeight(context) + taskMargin,
res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
outRect);
PointF taskDimension = getTaskDimension(context, dp);
float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
taskDimension.x, taskDimension.y);
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
int gravity = Gravity.TOP;
gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
} else {
int taskMargin = dp.overviewTaskMarginPx;
int proactiveRowAndMargin;
if (dp.isVerticalBarLayout()) {
// In Vertical Bar Layout the proactive row doesn't have its own space, it's inside
// the actions row.
proactiveRowAndMargin = 0;
} else {
proactiveRowAndMargin = res.getDimensionPixelSize(
R.dimen.overview_proactive_row_height)
+ res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
}
calculateTaskSizeInternal(context, dp,
dp.overviewTaskThumbnailTopMarginPx,
proactiveRowAndMargin + getOverviewActionsHeight(context) + taskMargin,
res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
outRect);
}
}
private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
int claimedSpaceAbove, int claimedSpaceBelow, int minimumHorizontalPadding,
Rect outRect) {
float taskWidth, taskHeight;
PointF taskDimension = getTaskDimension(context, dp);
Rect insets = dp.getInsets();
if (dp.isMultiWindowMode) {
WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
taskWidth = bounds.availableSize.x;
taskHeight = bounds.availableSize.y;
} else if (TaskView.CLIP_STATUS_AND_NAV_BARS) {
taskWidth = dp.availableWidthPx;
taskHeight = dp.availableHeightPx;
} else {
taskWidth = dp.widthPx;
taskHeight = dp.heightPx;
}
Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
@@ -240,14 +254,30 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
claimedSpaceBelow);
float scale = Math.min(
potentialTaskRect.width() / taskWidth,
potentialTaskRect.height() / taskHeight);
int outWidth = Math.round(scale * taskWidth);
int outHeight = Math.round(scale * taskHeight);
potentialTaskRect.width() / taskDimension.x,
potentialTaskRect.height() / taskDimension.y);
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
Gravity.apply(Gravity.CENTER, outWidth, outHeight, potentialTaskRect, outRect);
}
private PointF getTaskDimension(Context context, DeviceProfile dp) {
PointF dimension = new PointF();
if (dp.isMultiWindowMode) {
WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
dimension.x = bounds.availableSize.x;
dimension.y = bounds.availableSize.y;
} else if (TaskView.CLIP_STATUS_AND_NAV_BARS) {
dimension.x = dp.availableWidthPx;
dimension.y = dp.availableHeightPx;
} else {
dimension.x = dp.widthPx;
dimension.y = dp.heightPx;
}
return dimension;
}
/**
* Calculates the overview grid size for the provided device configuration.
*/
@@ -267,13 +297,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
* Calculates the modal taskView size for the provided device configuration
*/
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
Resources res = context.getResources();
calculateTaskSizeInternal(
context, dp,
res.getDimensionPixelSize(R.dimen.overview_task_margin),
getOverviewActionsHeight(context)
+ res.getDimensionPixelSize(R.dimen.overview_task_margin),
res.getDimensionPixelSize(R.dimen.overview_task_margin),
dp.overviewTaskMarginPx,
getOverviewActionsHeight(context) + dp.overviewTaskMarginPx,
dp.overviewTaskMarginPx,
outRect);
}
@@ -41,13 +41,4 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets {
public boolean hasTargets() {
return unfilteredApps.length != 0;
}
public boolean hasTask(int taskId) {
for (RemoteAnimationTargetCompat target : unfilteredApps) {
if (target.taskId == taskId) {
return true;
}
}
return false;
}
}
@@ -17,10 +17,11 @@ package com.android.quickstep;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -31,13 +32,13 @@ import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.RemoteTransitionCompat;
import java.util.function.Consumer;
import com.android.systemui.shared.system.TaskStackChangeListener;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS =
@@ -49,10 +50,24 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
private Runnable mLiveTileCleanUpHandler;
private Context mCtx;
private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId);
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
mLiveTileRestartListener);
}
}
};
TaskAnimationManager(Context ctx) {
mCtx = ctx;
}
@@ -114,9 +129,14 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
if (mLaunchOtherTaskHandler != null
&& mLastGestureState.getEndTarget() == RECENTS) {
mLaunchOtherTaskHandler.accept(appearedTaskTarget);
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
apps[0] = appearedTaskTarget;
recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
return;
}
if (mController != null) {
@@ -161,17 +181,12 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
return mCallbacks;
}
/**
* The passed-in handler is used to render side task launch animation in recents in live tile
* mode.
*/
public void setLaunchOtherTaskInLiveTileModeHandler(
Consumer<RemoteAnimationTargetCompat> handler) {
mLaunchOtherTaskHandler = handler;
public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
mLiveTileCleanUpHandler = cleanUpHandler;
}
public void setLiveTileCleanUpHandler(Runnable runnable) {
mLiveTileCleanUpHandler = runnable;
public void enableLiveTileRestartListener() {
ActivityManagerWrapper.getInstance().registerTaskStackListener(mLiveTileRestartListener);
}
/**
@@ -215,6 +230,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mLiveTileCleanUpHandler.run();
mLiveTileCleanUpHandler = null;
}
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mLiveTileRestartListener);
// Release all the target leashes
if (mTargets != null) {
@@ -231,7 +247,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTarget = null;
mLaunchOtherTaskHandler = null;
}
public void dump() {
@@ -176,7 +176,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
if (thumbnail != null) {
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
getActionsView().setCallbacks(new OverlayUICallbacksImpl(isAllowedByPolicy, task));
}
}
@@ -22,6 +22,7 @@ import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DU
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
@@ -200,8 +201,7 @@ public final class TaskViewUtils {
tsv.setPreview(targets.apps[targets.apps.length - 1]);
tsv.fullScreenProgress.value = 0;
tsv.recentsViewScale.value = 1;
tsv.gridProgress.value = gridProgress;
tsv.gridTranslationSecondary.value = gridTranslationSecondary;
tsv.taskSecondaryTranslation.value = gridTranslationSecondary;
tsv.setScroll(startScroll);
// Fade in the task during the initial 20% of the animation
@@ -214,7 +214,8 @@ public final class TaskViewUtils {
AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tsv.recentsViewScale,
AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tsv.gridProgress, AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
TaskViewSimulator finalTsv = tsv;
@@ -38,7 +38,8 @@ public class InputConsumerProxy {
private static final String TAG = "InputConsumerProxy";
private final InputConsumerController mInputConsumerController;
private final Supplier<InputConsumer> mConsumerSupplier;
private Runnable mCallback;
private Supplier<InputConsumer> mConsumerSupplier;
// The consumer is created lazily on demand.
private InputConsumer mInputConsumer;
@@ -48,8 +49,9 @@ public class InputConsumerProxy {
private boolean mDestroyPending = false;
public InputConsumerProxy(InputConsumerController inputConsumerController,
Supplier<InputConsumer> consumerSupplier) {
Runnable callback, Supplier<InputConsumer> consumerSupplier) {
mInputConsumerController = inputConsumerController;
mCallback = callback;
mConsumerSupplier = consumerSupplier;
}
@@ -64,9 +66,7 @@ public class InputConsumerProxy {
if (ev instanceof MotionEvent) {
onInputConsumerMotionEvent((MotionEvent) ev);
} else if (ev instanceof KeyEvent) {
if (mInputConsumer == null) {
mInputConsumer = mConsumerSupplier.get();
}
initInputConsumerIfNeeded();
mInputConsumer.onKeyEvent((KeyEvent) ev);
return true;
}
@@ -89,9 +89,7 @@ public class InputConsumerProxy {
if (action == ACTION_DOWN) {
mTouchInProgress = true;
if (mInputConsumer == null) {
mInputConsumer = mConsumerSupplier.get();
}
initInputConsumerIfNeeded();
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
@@ -115,4 +113,18 @@ public class InputConsumerProxy {
mDestroyed = true;
mInputConsumerController.setInputListener(null);
}
public void unregisterCallback() {
mCallback = null;
}
private void initInputConsumerIfNeeded() {
if (mInputConsumer == null) {
if (mCallback != null) {
mCallback.run();
}
mInputConsumer = mConsumerSupplier.get();
mConsumerSupplier = null;
}
}
}
@@ -0,0 +1,53 @@
/*
* 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.quickstep.util;
import androidx.annotation.UiThread;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import java.util.function.Supplier;
/**
* A factory that creates a input consumer for
* {@link com.android.quickstep.util.InputConsumerProxy}.
*/
public class InputProxyHandlerFactory implements Supplier<InputConsumer> {
private final BaseActivityInterface mActivityInterface;
private final GestureState mGestureState;
@UiThread
public InputProxyHandlerFactory(BaseActivityInterface activityInterface,
GestureState gestureState) {
mActivityInterface = activityInterface;
mGestureState = gestureState;
}
/**
* Called to create a input proxy for the running task
*/
@Override
public InputConsumer get() {
StatefulActivity activity = mActivityInterface.getCreatedActivity();
return activity == null ? InputConsumer.NO_OP
: new OverviewInputConsumer(mGestureState, activity, null, true);
}
}
@@ -24,7 +24,6 @@ import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -61,7 +60,10 @@ import com.android.systemui.plugins.ResourceProvider;
public class StaggeredWorkspaceAnim {
private static final int APP_CLOSE_ROW_START_DELAY_MS = 10;
// How long it takes to fade in each staggered row.
private static final int ALPHA_DURATION_MS = 250;
// Should be used for animations running alongside this StaggeredWorkspaceAnim.
public static final int DURATION_MS = 250;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -132,15 +134,15 @@ public class StaggeredWorkspaceAnim {
}
if (animateOverviewScrim) {
PendingAnimation pendingAnimation = new PendingAnimation(ALPHA_DURATION_MS);
PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS);
addScrimAnimationForState(launcher, NORMAL, pendingAnimation);
mAnimators.play(pendingAnimation.buildAnim());
}
addDepthAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
addDepthAnimationForState(launcher, NORMAL, DURATION_MS);
mAnimators.play(launcher.getDragLayer().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
.setDuration(ALPHA_DURATION_MS));
.setDuration(DURATION_MS));
mAnimators.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -182,8 +184,7 @@ public class StaggeredWorkspaceAnim {
*/
private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
StateAnimationConfig config = new StateAnimationConfig();
config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER
| SKIP_TASKBAR;
config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
config.duration = 0;
// setRecentsAttachedToAppWindow() will animate recents out.
launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.util;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
@@ -36,7 +35,6 @@ import android.util.IntProperty;
import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -79,7 +77,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
private final boolean mIsRecentsRtl;
private final Rect mTaskRect = new Rect();
private final Rect mGridRect = new Rect();
private boolean mDrawsBelowRecents;
private final PointF mPivot = new PointF();
private DeviceProfile mDp;
@@ -98,22 +95,18 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
private final FullscreenDrawParams mCurrentFullscreenParams;
public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
public final AnimatedFloat gridTranslationSecondary = new AnimatedFloat();
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat();
public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat();
public final AnimatedFloat gridProgress = new AnimatedFloat();
private final ScrollState mScrollState = new ScrollState();
// Cached calculations
private boolean mLayoutValid = false;
private boolean mScrollValid = false;
private int mOrientationStateId;
private final int mTaskThumbnailPadding;
private final int mRowSpacing;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -125,8 +118,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mOrientationStateId = mOrientationState.getStateId();
Resources resources = context.getResources();
mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
mTaskThumbnailPadding = (int) resources.getDimension(R.dimen.task_thumbnail_top_margin);
mRowSpacing = (int) resources.getDimension(R.dimen.overview_grid_row_spacing);
}
/**
@@ -268,7 +259,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mOrientationStateId = mOrientationState.getStateId();
getFullScreenScale();
mSizeStrategy.calculateGridSize(mContext, mDp, mGridRect);
mThumbnailData.rotation = mOrientationState.getDisplayRotation();
// mIsRecentsRtl is the inverse of TaskView RTL.
@@ -309,34 +299,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mMatrix.postTranslate(insets.left, insets.top);
mMatrix.postScale(scale, scale);
// Apply TaskView matrix: gridProgress related properties
float interpolatedGridProgress = ACCEL_DEACCEL.getInterpolation(gridProgress.value);
final int boxLength = (int) Math.max(taskWidth, taskHeight);
float availableHeight = mGridRect.height();
float rowHeight = (availableHeight - mRowSpacing) / 2;
float gridScale = rowHeight / (boxLength + mTaskThumbnailPadding);
scale = Utilities.mapRange(interpolatedGridProgress, 1f, gridScale);
mMatrix.postScale(scale, scale, mIsRecentsRtl ? 0 : taskWidth, 0);
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
Utilities.mapRange(interpolatedGridProgress, 0, gridTranslationSecondary.value));
// Apply TaskView matrix: task rect and grid rect difference
float scaledWidth = taskWidth * gridScale;
float taskGridHorizontalDiff;
if (mIsRecentsRtl) {
float taskRight = mTaskRect.left + scaledWidth;
taskGridHorizontalDiff = mGridRect.right - taskRight;
} else {
float taskLeft = mTaskRect.right - scaledWidth;
taskGridHorizontalDiff = mGridRect.left - taskLeft;
}
float taskGridVerticalDiff =
mGridRect.top + mTaskThumbnailPadding * gridScale - mTaskRect.top;
mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
Utilities.mapRange(interpolatedGridProgress, 0, taskGridHorizontalDiff));
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
Utilities.mapRange(interpolatedGridProgress, 0, taskGridVerticalDiff));
// Apply TaskView matrix: translate, scroll
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
@@ -21,6 +21,7 @@ import android.util.AttributeSet;
import android.util.FloatProperty;
import android.widget.Button;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState;
@@ -40,30 +41,32 @@ public class ClearAllButton extends Button implements PageCallbacks {
}
};
private final StatefulActivity mActivity;
private float mScrollAlpha = 1;
private float mContentAlpha = 1;
private float mVisibilityAlpha = 1;
private float mGridProgress = 1;
private boolean mIsRtl;
private final float mOriginalTranslationX, mOriginalTranslationY;
private float mNormalTranslationPrimary;
private float mGridTranslationPrimary;
private float mGridTranslationSecondary;
private float mGridScrollOffset;
private float mOffsetTranslationPrimary;
private int mScrollOffset;
private int mSidePadding;
public ClearAllButton(Context context, AttributeSet attrs) {
super(context, attrs);
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
mOriginalTranslationX = getTranslationX();
mOriginalTranslationY = getTranslationY();
mActivity = StatefulActivity.fromContext(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl);
mSidePadding = orientationHandler.getClearAllSidePadding(getRecentsView(), mIsRtl);
}
private RecentsView getRecentsView() {
@@ -96,25 +99,27 @@ public class ClearAllButton extends Button implements PageCallbacks {
}
@Override
public void onPageScroll(ScrollState scrollState) {
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
RecentsView recentsView = getRecentsView();
if (recentsView == null) {
return;
}
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
if (orientationSize == 0) {
return;
}
float shift;
if (mIsRtl) {
shift = Math.min(scrollState.scrollFromEdge, orientationSize);
} else {
shift = Math.min(scrollState.scrollFromEdge,
orientationSize + getGridTrans(mGridTranslationPrimary))
- getGridTrans(mGridTranslationPrimary);
int leftEdgeScroll = recentsView.getLeftMostChildScroll();
float adjustedScrollFromEdge = scrollState.scrollFromEdge - leftEdgeScroll;
float shift = Math.min(adjustedScrollFromEdge, orientationSize);
mNormalTranslationPrimary = mIsRtl ? -shift : shift;
if (!gridEnabled) {
mNormalTranslationPrimary += mSidePadding;
}
mNormalTranslationPrimary = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
applyPrimaryTranslation();
orientationHandler.getSecondaryViewTranslate().set(this,
orientationHandler.getSecondaryValue(mOriginalTranslationX, mOriginalTranslationY));
applySecondaryTranslation();
mScrollAlpha = 1 - shift / orientationSize;
updateAlpha();
}
@@ -130,11 +135,26 @@ public class ClearAllButton extends Button implements PageCallbacks {
applyPrimaryTranslation();
}
public void setGridTranslationSecondary(float gridTranslationSecondary) {
mGridTranslationSecondary = gridTranslationSecondary;
applyPrimaryTranslation();
}
public void setGridScrollOffset(float gridScrollOffset) {
mGridScrollOffset = gridScrollOffset;
}
public void setOffsetTranslationPrimary(float offsetTranslationPrimary) {
mOffsetTranslationPrimary = offsetTranslationPrimary;
applyPrimaryTranslation();
}
public float getScrollAdjustment(boolean gridEnabled) {
float scrollAdjustment = 0;
if (gridEnabled) {
scrollAdjustment += mGridTranslationPrimary;
scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
}
scrollAdjustment += mOffsetTranslationPrimary;
return scrollAdjustment;
}
@@ -160,10 +180,31 @@ public class ClearAllButton extends Button implements PageCallbacks {
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
orientationHandler.getPrimaryViewTranslate().set(this,
mNormalTranslationPrimary + getGridTrans(mGridTranslationPrimary));
orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
+ mNormalTranslationPrimary + mOffsetTranslationPrimary + getGridTrans(
mGridTranslationPrimary));
}
private void applySecondaryTranslation() {
RecentsView recentsView = getRecentsView();
if (recentsView == null) {
return;
}
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
orientationHandler.getSecondaryViewTranslate().set(this,
orientationHandler.getSecondaryValue(0f, getOriginalTranslationY())
+ getGridTrans(mGridTranslationSecondary));
}
private float getGridTrans(float endTranslation) {
return mGridProgress > 0 ? endTranslation : 0;
}
/**
* Get the Y translation that is set in the original layout position, before scrolling.
*/
private float getOriginalTranslationY() {
return mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx / 2.0f;
}
}
@@ -29,6 +29,7 @@ import android.widget.FrameLayout;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.util.MultiValueAlpha;
@@ -144,6 +145,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
public void setInsets(Rect insets) {
mInsets.set(insets);
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
updateHorizontalPadding();
}
public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
@@ -187,6 +189,10 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
}
private void updateHorizontalPadding() {
setPadding(mInsets.left, 0, mInsets.right, 0);
}
/** Updates vertical margins for different navigation mode or configuration changes. */
public void updateVerticalMargin(Mode mode) {
LayoutParams actionParams = (LayoutParams) findViewById(
@@ -196,6 +202,13 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
getBottomVerticalMargin(mode));
}
/**
* Set the device profile for this view to draw with.
*/
public void setDp(DeviceProfile dp) {
requestLayout();
}
protected int getBottomVerticalMargin(Mode mode) {
int bottomMargin;
int orientation = getResources().getConfiguration().orientation;
@@ -27,6 +27,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
@@ -34,6 +35,7 @@ import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
@@ -50,6 +52,7 @@ import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
@@ -61,6 +64,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -129,8 +133,11 @@ import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.util.SurfaceTransactionApplier;
@@ -142,6 +149,8 @@ import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.wm.shell.pip.IPipAnimationListener;
@@ -301,6 +310,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
protected final Rect mTempRect = new Rect();
protected final RectF mTempRectF = new RectF();
private final PointF mTempPointF = new PointF();
private float mFullscreenScale;
private static final int DISMISS_TASK_DURATION = 300;
private static final int ADDITION_TASK_DURATION = 200;
@@ -310,7 +320,6 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
protected final T mActivity;
private final float mFastFlingVelocity;
private final RecentsModel mModel;
private final int mTaskTopMargin;
private final int mRowSpacing;
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
@@ -529,8 +538,6 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mTaskTopMargin = getResources()
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
mSquaredTouchSlop = squaredTouchSlop(context);
@@ -717,6 +724,72 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
super.draw(canvas);
}
public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
if (mRunningTaskId != -1 && mRunningTaskId == taskId &&
getLiveTileParams().getTargetSet().findTask(taskId) != null) {
launchSideTaskInLiveTileMode(taskId, getLiveTileParams().getTargetSet().apps);
}
}
public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
AnimatorSet anim = new AnimatorSet();
TaskView taskView = getTaskView(taskId);
if (taskView == null || !isTaskViewVisible(taskView)) {
// TODO: Refine this animation.
SurfaceTransactionApplier surfaceApplier =
new SurfaceTransactionApplier(mActivity.getDragLayer());
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
appAnimator.setInterpolator(ACCEL_DEACCEL);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@Override
public void onUpdate(float percent) {
SurfaceParams.Builder builder = new SurfaceParams.Builder(
apps[apps.length - 1].leash);
Matrix matrix = new Matrix();
matrix.postScale(percent, percent);
matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2,
mActivity.getDeviceProfile().heightPx * (1 - percent) / 2);
builder.withAlpha(percent).withMatrix(matrix);
surfaceApplier.scheduleApply(builder.build());
}
});
anim.play(appAnimator);
} else {
TaskViewUtils.composeRecentsLaunchAnimator(
anim, taskView, apps,
mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */,
mActivity.getStateManager(), this,
getDepthController());
}
anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animator) {
cleanUp(false);
}
@Override
public void onAnimationCancel(Animator animator) {
cleanUp(true);
}
private void cleanUp(boolean canceled) {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
if (canceled) {
mRecentsAnimationController = null;
} else {
mSizeStrategy.onLaunchTaskSuccess();
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
}
}
});
anim.start();
}
private void updateTaskStartIndex(View affectingView) {
if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) {
int childCount = getChildCount();
@@ -744,7 +817,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
mOverviewFullscreenEnabled, showAsGrid());
int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
mOverviewFullscreenEnabled, showAsGrid()));
mOverviewFullscreenEnabled));
int taskEnd = taskStart + taskSize;
return (taskStart >= start && taskStart <= end) || (taskEnd >= start
&& taskEnd <= end);
@@ -1022,7 +1095,6 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = 0;
mLiveTileTaskViewSimulator.fullScreenProgress.value = 0;
mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
mLiveTileTaskViewSimulator.gridProgress.value = 0;
}
if (mRunningTaskTileHidden) {
setRunningTaskHidden(mRunningTaskTileHidden);
@@ -1066,7 +1138,9 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
public void setInsets(Rect insets) {
mInsets.set(insets);
resetPaddingFromTaskSize();
mLiveTileTaskViewSimulator.setDp(mActivity.getDeviceProfile());
DeviceProfile dp = mActivity.getDeviceProfile();
mLiveTileTaskViewSimulator.setDp(dp);
mActionsView.setDp(dp);
}
private void resetPaddingFromTaskSize() {
@@ -1075,7 +1149,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
mTaskWidth = mTempRect.width();
mTaskHeight = mTempRect.height();
mTempRect.top -= mTaskTopMargin;
mTempRect.top -= dp.overviewTaskThumbnailTopMarginPx;
setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
dp.widthPx - mInsets.right - mTempRect.right,
dp.heightPx - mInsets.bottom - mTempRect.bottom);
@@ -1092,6 +1166,10 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
*/
private void updateTaskSize() {
final int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
}
float accumulatedTranslationX = 0;
float[] fullscreenTranslations = new float[taskCount];
int firstNonHomeTaskIndex = 0;
@@ -1106,8 +1184,11 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
taskView.updateTaskSize();
fullscreenTranslations[i] += accumulatedTranslationX;
// Compensate space caused by TaskView scaling.
float widthDiff =
taskView.getLayoutParams().width * (1 - taskView.getFullscreenScale());
// Compensate page spacing widening caused by RecentsView scaling.
widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale);
float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff;
fullscreenTranslations[i] += fullscreenTranslationX;
accumulatedTranslationX += fullscreenTranslationX;
@@ -1181,13 +1262,13 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
View page = getPageAt(i);
mScrollState.updateInterpolation(mActivity.getDeviceProfile(),
mOrientationHandler.getChildStartWithTranslation(page));
((PageCallbacks) page).onPageScroll(mScrollState);
((PageCallbacks) page).onPageScroll(mScrollState, mOverviewGridEnabled);
}
}
@Override
protected int getDestinationPage(int scaledScroll) {
if (mGridProgress == 0) {
if (!showAsGrid()) {
return super.getDestinationPage(scaledScroll);
}
@@ -1600,10 +1681,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
final int boxLength = Math.max(mTaskWidth, mTaskHeight);
float availableHeight = mLastComputedGridSize.height();
float rowHeight = (availableHeight - mRowSpacing) / 2;
float gridScale = rowHeight / (boxLength + mTaskTopMargin);
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
int topRowWidth = 0;
int bottomRowWidth = 0;
float topAccumulatedTranslationX = 0;
@@ -1621,43 +1699,17 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
continue;
}
taskView.setGridScale(gridScale);
float scaledWidth = taskView.getLayoutParams().width * gridScale;
float taskGridHorizontalDiff;
if (mIsRtl) {
float taskRight = mLastComputedTaskSize.left + scaledWidth;
taskGridHorizontalDiff = mLastComputedGridSize.right - taskRight;
} else {
float taskLeft = mLastComputedTaskSize.right - scaledWidth;
taskGridHorizontalDiff = mLastComputedGridSize.left - taskLeft;
}
gridTranslations[i] -= taskGridHorizontalDiff;
taskView.setGridOffsetTranslationX(taskGridHorizontalDiff);
float taskGridVerticalDiff = mLastComputedGridSize.top + mTaskTopMargin * gridScale
- mLastComputedTaskSize.top;
// Off-set gap due to task scaling.
float widthDiff = taskView.getLayoutParams().width * (1 - gridScale);
float gridScaleTranslationX = mIsRtl ? widthDiff : -widthDiff;
gridTranslations[i] += gridScaleTranslationX;
// Visible offset caused by having scaling pivot on top-right.
taskView.setNonRtlVisibleOffset(mIsRtl ? 0 : widthDiff);
if (topRowWidth <= bottomRowWidth) {
gridTranslations[i] += topAccumulatedTranslationX;
topRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing;
topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
topSet.add(i);
taskView.setGridTranslationY(taskGridVerticalDiff);
taskView.setGridTranslationY(0);
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; bottomSet.contains(j); j--) {
widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale
+ mPageSpacing;
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -1665,26 +1717,39 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
topAccumulatedTranslationX += gridTranslationX;
} else {
gridTranslations[i] += bottomAccumulatedTranslationX;
bottomRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing;
bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
bottomSet.add(i);
// Move into bottom row.
float heightOffset = (boxLength + mTaskTopMargin) * gridScale + mRowSpacing;
taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
taskView.setGridTranslationY(heightOffset);
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; topSet.contains(j); j--) {
widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale
+ mPageSpacing;
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += gridTranslationX;
bottomAccumulatedTranslationX += gridTranslationX;
}
topAccumulatedTranslationX += gridScaleTranslationX;
bottomAccumulatedTranslationX += gridScaleTranslationX;
}
// If the first non-home task does not take full width of task Rect, shift all tasks
// accordingly without affecting scrolls.
int firstTaskWidth = getTaskViewAt(firstNonHomeTaskIndex).getLayoutParams().width;
float firstNonHomeTaskOffset = firstTaskWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 0
: mTaskWidth - firstTaskWidth;
float offsetTranslation = mIsRtl ? firstNonHomeTaskOffset : -firstNonHomeTaskOffset;
// We need to maintain first non-home task's grid translation at 0, now shift translation
// of all the TaskViews to achieve that.
for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
TaskView taskView = getTaskViewAt(i);
taskView.setGridTranslationX(
gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
taskView.setGridOffsetTranslationX(offsetTranslation);
}
// Use the accumulated translation of the longer row.
@@ -1700,7 +1765,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
shorterRowCompensation = bottomRowWidth - topRowWidth;
}
} else {
if (!topSet.contains(taskCount - 1)) {
if (bottomSet.contains(taskCount - 1)) {
shorterRowCompensation = topRowWidth - bottomRowWidth;
}
}
@@ -1721,14 +1786,14 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
clearAllAccumulatedTranslation + clearAllShorterRowCompensation
+ clearAllShortTotalCompensation;
// We need to maintain first non-home task's grid translation at 0, now shift translation
// of all the TaskViews to achieve that.
for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
getTaskViewAt(i).setGridTranslationX(
gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
}
mClearAllButton.setGridTranslationPrimary(
clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
mClearAllButton.setGridTranslationSecondary(
boxLength - mTaskHeight / 2f + mRowSpacing / 2f);
mClearAllButton.setGridScrollOffset(
mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
: mLastComputedTaskSize.right - mLastComputedGridSize.right);
mClearAllButton.setOffsetTranslationPrimary(offsetTranslation);
setGridProgress(mGridProgress);
}
@@ -1753,7 +1818,6 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
for (int i = 0; i < taskCount; i++) {
getTaskViewAt(i).setGridProgress(gridProgress);
}
mLiveTileTaskViewSimulator.gridProgress.value = gridProgress;
mClearAllButton.setGridProgress(gridProgress);
}
@@ -1801,8 +1865,10 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
/**
* Updates the page UI based on scroll params.
*
* @param gridEnabled whether Overveiw is currently showing as 2 rows grid
*/
default void onPageScroll(ScrollState scrollState) {}
default void onPageScroll(ScrollState scrollState, boolean gridEnabled) {}
}
public static class ScrollState extends CurveProperties {
@@ -2297,7 +2363,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
// Update the pivots such that when the task is scaled, it fills the full page
getTaskSize(mTempRect);
getPagedViewOrientedState().getFullScreenScaleAndPivot(
mFullscreenScale = getPagedViewOrientedState().getFullScreenScaleAndPivot(
mTempRect, mActivity.getDeviceProfile(), mTempPointF);
setPivotX(mTempPointF.x);
setPivotY(mTempPointF.y);
@@ -2485,7 +2551,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
if (child == mSplitHiddenTaskView) {
int left = newScroll[i] + getPaddingStart();
int topMargin = mSplitHiddenTaskView.getThumbnailTopMargin();
int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1];
mSplitHiddenTaskView.layout(left, top,
left + mSplitHiddenTaskView.getWidth(),
@@ -2858,22 +2924,42 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
@Override
protected int computeMinScroll() {
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
if (mIsRtl && mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
// so use the leftmost task as the min scroll.
if (mIsRtl) {
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
return getScrollForPage(mTaskViewStartIndex);
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
if (mIsRtl) {
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
}
return getScrollForPage(mTaskViewStartIndex);
return getLeftMostChildScroll();
}
return super.computeMinScroll();
}
/**
* Returns page scroll of the left most child.
*/
public int getLeftMostChildScroll() {
if (mIsRtl) {
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
}
return getScrollForPage(mTaskViewStartIndex);
}
@Override
protected int computeMaxScroll() {
if (getTaskViewCount() > 0) {
if (!mIsRtl && mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
// so use the rightmost task as the min scroll.
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
if (mIsRtl) {
return getScrollForPage(mTaskViewStartIndex);
}
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
}
return super.computeMaxScroll();
}
@Override
protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
ComputePageScrollsLogic scrollLogic) {
@@ -2919,26 +3005,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
return super.getChildVisibleSize(index);
}
return (int) (super.getChildVisibleSize(index) * taskView.getSizeAdjustment(
mOverviewFullscreenEnabled, showAsGrid()));
}
@Override
protected int computeMaxScroll() {
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
// so use the rightmost task as the min scroll.
if (mIsRtl) {
return getScrollForPage(mTaskViewStartIndex);
}
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
if (mIsRtl) {
return getScrollForPage(mTaskViewStartIndex);
}
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
}
return super.computeMaxScroll();
mOverviewFullscreenEnabled));
}
public ClearAllButton getClearAllButton() {
@@ -3160,7 +3227,9 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
MAIN_EXECUTOR.execute(() -> {
// Needed for activities that auto-enter PiP, which will not trigger a remote
// animation to be created
mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
if (mActivity != null) {
mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
}
});
}
}
@@ -58,7 +58,6 @@ public class TaskMenuView extends AbstractFloatingView {
private static final int REVEAL_OPEN_DURATION = 150;
private static final int REVEAL_CLOSE_DURATION = 100;
private final float mThumbnailTopMargin;
private BaseDraggingActivity mActivity;
private TextView mTaskName;
private AnimatorSet mOpenCloseAnimator;
@@ -73,7 +72,6 @@ public class TaskMenuView extends AbstractFloatingView {
super(context, attrs, defStyleAttr);
mActivity = BaseDraggingActivity.fromContext(context);
mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
setClipToOutline(true);
}
@@ -123,14 +121,15 @@ public class TaskMenuView extends AbstractFloatingView {
}
public void setPosition(float x, float y, PagedOrientationHandler pagedOrientationHandler) {
float adjustedY = y + mThumbnailTopMargin;
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
float adjustedY = y + taskTopMargin;
// Changing pivot to make computations easier
// NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
// which would render the X and Y position set here incorrect
setPivotX(0);
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
// In tablet, set pivotY to original position without mThumbnailTopMargin adjustment.
setPivotY(-mThumbnailTopMargin);
setPivotY(-taskTopMargin);
} else {
setPivotY(0);
}
@@ -440,13 +440,14 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
}
/**
* Returns whether the snapshot is real.
* Returns whether the snapshot is real. If the device is locked for the user of the task,
* the snapshot used will be an app-theme generated snapshot instead of a real snapshot.
*/
public boolean isRealSnapshot() {
if (mThumbnailData == null) {
return false;
}
return mThumbnailData.isRealSnapshot;
return mThumbnailData.isRealSnapshot && !mTask.isLocked;
}
/**
@@ -279,7 +279,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private float mFullscreenProgress;
private float mGridProgress;
private float mFullscreenScale = 1;
private float mGridScale = 1;
private final FullscreenDrawParams mCurrentFullscreenParams;
private final StatefulActivity mActivity;
@@ -298,7 +297,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private float mGridTranslationY;
// Offset translation does not affect scroll calculation.
private float mGridOffsetTranslationX;
private float mNonRtlVisibleOffset;
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
@@ -376,7 +374,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams);
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
setOutlineProvider(mOutlineProvider);
}
@@ -673,17 +672,14 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
}
public int getThumbnailTopMargin() {
return (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
}
public void setOrientationState(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
int taskIconMargin = (int) getResources().getDimension(R.dimen.task_icon_top_margin);
int taskIconHeight = (int) getResources().getDimension(R.dimen.task_thumbnail_icon_size);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
int taskIconMargin = deviceProfile.overviewTaskMarginPx;
int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
switch (orientationHandler.getRotation()) {
case ROTATION_90:
@@ -694,7 +690,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
break;
case ROTATION_180:
iconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
iconParams.bottomMargin = -thumbnailPadding;
iconParams.bottomMargin = -snapshotParams.topMargin;
iconParams.leftMargin = iconParams.rightMargin = 0;
iconParams.topMargin = taskIconMargin;
break;
@@ -711,8 +707,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
iconParams.topMargin = taskIconMargin;
break;
}
mSnapshotView.setLayoutParams(snapshotParams);
iconParams.width = iconParams.height = taskIconHeight;
mIconView.setLayoutParams(iconParams);
mIconView.setRotation(orientationHandler.getDegreesRotated());
snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
mSnapshotView.setLayoutParams(snapshotParams);
if (mMenuView != null) {
mMenuView.onRotationChanged();
@@ -792,8 +792,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
@Override
public void onRecycle() {
mFullscreenTranslationX = mGridTranslationX = mGridTranslationY =
mGridOffsetTranslationX = mBoxTranslationY = mNonRtlVisibleOffset = 0f;
mFullscreenTranslationX = mGridTranslationX =
mGridTranslationY = mGridOffsetTranslationX = mBoxTranslationY = 0f;
resetViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
@@ -803,7 +803,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
@Override
public void onPageScroll(ScrollState scrollState) {
public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
// Don't do anything if it's modal.
if (mModalness > 0) {
return;
@@ -906,11 +906,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
return mFullscreenScale;
}
public void setGridScale(float gridScale) {
mGridScale = gridScale;
applyScale();
}
/**
* Moves TaskView between carousel and 2 row grid.
*
@@ -927,8 +922,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
float scale = 1;
float fullScreenProgress = EXAGGERATED_EASE.getInterpolation(mFullscreenProgress);
scale *= Utilities.mapRange(fullScreenProgress, 1f, mFullscreenScale);
float gridProgress = ACCEL_DEACCEL.getInterpolation(mGridProgress);
scale *= Utilities.mapRange(gridProgress, 1f, mGridScale);
setScaleX(scale);
setScaleY(scale);
}
@@ -991,10 +984,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
applyTranslationX();
}
public void setNonRtlVisibleOffset(float nonRtlVisibleOffset) {
mNonRtlVisibleOffset = nonRtlVisibleOffset;
}
public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
float scrollAdjustment = 0;
if (fullscreenEnabled) {
@@ -1006,22 +995,19 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
return scrollAdjustment;
}
public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) {
float offsetAdjustment = getScrollAdjustment(fullscreenEnabled, gridEnabled);
if (gridEnabled) {
offsetAdjustment += mGridOffsetTranslationX + mNonRtlVisibleOffset;
offsetAdjustment += mGridOffsetTranslationX;
}
return offsetAdjustment;
}
public float getSizeAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
public float getSizeAdjustment(boolean fullscreenEnabled) {
float sizeAdjustment = 1;
if (fullscreenEnabled) {
sizeAdjustment *= mFullscreenScale;
}
if (gridEnabled) {
sizeAdjustment *= mGridScale;
}
return sizeAdjustment;
}
@@ -1083,17 +1069,17 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private static final class TaskOutlineProvider extends ViewOutlineProvider {
private final int mMarginTop;
private int mMarginTop;
private FullscreenDrawParams mFullscreenParams;
TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) {
mMarginTop = context.getResources().getDimensionPixelSize(
R.dimen.task_thumbnail_top_margin);
TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams, int topMargin) {
mMarginTop = topMargin;
mFullscreenParams = fullscreenParams;
}
public void setFullscreenParams(FullscreenDrawParams params) {
public void updateParams(FullscreenDrawParams params, int topMargin) {
mFullscreenParams = params;
mMarginTop = topMargin;
}
@Override
@@ -1216,7 +1202,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
thumbnail.setFullscreenParams(mCurrentFullscreenParams);
mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams);
mOutlineProvider.updateParams(
mCurrentFullscreenParams,
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
invalidateOutline();
}
@@ -1238,8 +1226,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
void updateTaskSize() {
ViewGroup.LayoutParams params = getLayoutParams();
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
final int thumbnailPadding = (int) getResources().getDimension(
R.dimen.task_thumbnail_top_margin);
final int thumbnailPadding =
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
int taskWidth = lastComputedTaskSize.width();
+10
View File
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M20.41,4.94l-1.35,-1.35c-0.78,-0.78 -2.05,-0.78 -2.83,0L3,16.82L3,21h4.18L20.41,7.77c0.79,-0.78 0.79,-2.05 0,-2.83zM6.41,19.06L5,19v-1.36l9.82,-9.82 1.41,1.41 -9.82,9.83z"/>
</vector>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="@dimen/widget_reconfigure_button_size"
android:height="@dimen/widget_reconfigure_button_size">
<shape
android:shape="rectangle">
<solid android:color="?android:attr/colorAccent" />
<corners android:radius="@dimen/widget_reconfigure_button_corner_radius" />
</shape>
</item>
<item
android:gravity="center"
android:padding="@dimen/widget_reconfigure_button_padding"
android:drawable="@drawable/gm_edit_24"
android:color="?android:attr/colorPrimary" />
</layer-list>
+1
View File
@@ -26,6 +26,7 @@
android:clipChildren="true"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:paddingTop="@dimen/all_apps_header_top_padding"
launcher:pageIndicator="@+id/tabs" >
<include layout="@layout/all_apps_rv_layout" />
+12
View File
@@ -73,5 +73,17 @@
android:src="@drawable/ic_widget_resize_handle"
android:tint="?android:attr/colorAccent" />
<ImageButton
android:id="@+id/widget_reconfigure_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/widget_reconfigure_button_padding"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/widget_reconfigure_button_margin"
android:layout_marginEnd="@dimen/widget_reconfigure_button_margin"
android:src="@drawable/widget_reconfigure_button_frame"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone" />
</FrameLayout>
</com.android.launcher3.AppWidgetResizeFrame>
+4 -2
View File
@@ -129,11 +129,10 @@
<!-- numHotseatIcons defaults to numColumns, if not specified -->
<attr name="numHotseatIcons" format="integer" />
<attr name="dbFile" format="string" />
<!-- numAllAppsColumns defaults to numColumns, if not specified -->
<attr name="numAllAppsColumns" format="integer" />
<attr name="defaultLayoutId" format="reference" />
<attr name="demoModeLayoutId" format="reference" />
<attr name="isScalable" format="boolean" />
<attr name="devicePaddingId" format="reference" />
</declare-styleable>
@@ -170,6 +169,9 @@
<attr name="allAppsIconSize" format="float" />
<!-- allAppsIconTextSize defaults to iconTextSize, if not specified -->
<attr name="allAppsIconTextSize" format="float" />
<!-- numAllAppsColumns defaults to GridDisplayOption.numColumns, if not specified -->
<attr name="numAllAppsColumns" format="integer" />
</declare-styleable>
<declare-styleable name="CellLayout">
+11
View File
@@ -56,6 +56,12 @@
<dimen name="resize_frame_background_padding">24dp</dimen>
<dimen name="resize_frame_margin">22dp</dimen>
<!-- App widget reconfigure button -->
<dimen name="widget_reconfigure_button_corner_radius">14dp</dimen>
<dimen name="widget_reconfigure_button_padding">6dp</dimen>
<dimen name="widget_reconfigure_button_margin">32dp</dimen>
<dimen name="widget_reconfigure_button_size">36dp</dimen>
<!-- Fast scroll -->
<dimen name="fastscroll_track_min_width">6dp</dimen>
<dimen name="fastscroll_track_max_width">8dp</dimen>
@@ -286,4 +292,9 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
<!-- Overview placeholder to compile in Launcer3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_size_grid">0dp</dimen>
<dimen name="overview_task_margin">0dp</dimen>
</resources>
+11 -2
View File
@@ -380,9 +380,18 @@
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_body">Work apps can\'t send you notifications, use your battery, or access your location</string>
<string name="work_apps_paused_body">Work apps cant send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\t send you notifications, use your battery, or access your location</string>
<string name="work_apps_paused_content_description">Work profile is paused. Work apps cant send you notifications, use your battery, or access your location</string>
<!-- string shown in educational banner about work profile -->
<string name="work_apps_paused_edu_banner">Work apps are badged and visible to your IT admin</string>
<!-- button string shown to dismiss work tab education -->
<string name="work_apps_paused_edu_accept">Got it</string>
<!-- button string shown pause work profile -->
<string name="work_apps_pause_btn_text">Pause work apps</string>
<!-- button string shown enable work profile -->
<string name="work_apps_enable_btn_text">Turn on</string>
<!-- A hint shown in launcher settings develop options filter box -->
<string name="developer_options_filter_hint">Filter</string>
@@ -38,7 +38,7 @@
<workspaceBottomPadding
launcher:a="0.50"
launcher:b="0"
launcher:c="-16dp"/>
launcher:c="16dp"/>
<hotseatBottomPadding
launcher:a="0.50"
launcher:b="0"
@@ -82,7 +82,7 @@ public final class WidgetsListAdapterTest {
mTestProfile.numColumns = 5;
mUserHandle = Process.myUserHandle();
mAdapter = new WidgetsListAdapter(mContext, mMockLayoutInflater, mMockWidgetCache,
mIconCache, null, null);
mIconCache, null, null, null);
mAdapter.registerAdapterDataObserver(mListener);
doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
@@ -105,7 +105,8 @@ public final class WidgetsListHeaderViewHolderBinderTest {
mWidgetPreviewLoader,
mIconCache,
/* iconClickListener= */ view -> {},
/* iconLongClickListener= */ view -> false);
/* iconLongClickListener= */ view -> false,
/* searchBarUIHelper= */ null);
mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
}
@@ -105,7 +105,8 @@ public final class WidgetsListSearchHeaderViewHolderBinderTest {
mWidgetPreviewLoader,
mIconCache,
/* iconClickListener= */ view -> {},
/* iconLongClickListener= */ view -> false);
/* iconLongClickListener= */ view -> false,
/* searchBarUIHelper= */ null);
mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
}
@@ -111,7 +111,8 @@ public final class WidgetsListTableViewHolderBinderTest {
mWidgetPreviewLoader,
mIconCache,
/* iconClickListener= */ view -> {},
/* iconLongClickListener= */ view -> false);
/* iconLongClickListener= */ view -> false,
/* searchBarUIHelper= */ null);
mViewHolderBinder = new WidgetsListTableViewHolderBinder(
mContext,
LayoutInflater.from(mTestActivity),
@@ -98,13 +98,6 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
| TYPE_SNACKBAR | TYPE_WIDGET_RESIZE_FRAME | TYPE_LISTENER;
// When these types of floating views are open, hide the taskbar hotseat and show the real one.
public static final int TYPE_REPLACE_TASKBAR_WITH_HOTSEAT = TYPE_FOLDER | TYPE_ACTION_POPUP;
// Hide the taskbar when these types of floating views are open.
public static final int TYPE_HIDE_TASKBAR = TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP;
public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
& ~TYPE_ALL_APPS_EDU;
@@ -22,6 +22,7 @@ import android.util.SizeF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import androidx.annotation.Nullable;
@@ -74,6 +75,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private LauncherAppWidgetHostView mWidgetView;
private CellLayout mCellLayout;
private DragLayer mDragLayer;
private ImageButton mReconfigureButton;
private Rect mWidgetPadding;
@@ -211,6 +213,17 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mDragHandles[INDEX_RIGHT].setVisibility(GONE);
}
mReconfigureButton = (ImageButton) findViewById(R.id.widget_reconfigure_button);
if (info.isReconfigurable()) {
mReconfigureButton.setVisibility(VISIBLE);
mReconfigureButton.setOnClickListener(view -> mLauncher
.getAppWidgetHost()
.startConfigActivity(
mLauncher,
mWidgetView.getAppWidgetId(),
Launcher.REQUEST_RECONFIGURE_APPWIDGET));
}
// When we create the resize frame, we first mark all cells as unoccupied. The appropriate
// cells (same if not resized, or different) will be marked as occupied when the resize
// frame is dismissed.
@@ -582,6 +595,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
return false;
}
private boolean isTouchOnReconfigureButton(MotionEvent ev) {
int xFrame = (int) ev.getX() - getLeft();
int yFrame = (int) ev.getY() - getTop();
mReconfigureButton.getHitRect(sTmpRect);
return sTmpRect.contains(xFrame, yFrame);
}
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
int action = ev.getAction();
@@ -609,6 +629,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) {
return true;
}
// Keep the resize frame open but let a click on the reconfigure button fall through to the
// button's OnClickListener.
if (isTouchOnReconfigureButton(ev)) {
return false;
}
close(false);
return false;
}
+39 -5
View File
@@ -52,8 +52,8 @@ public class DevicePaddings {
ArrayList<DevicePadding> mDevicePaddings = new ArrayList<>();
public DevicePaddings(Context context) {
try (XmlResourceParser parser = context.getResources().getXml(R.xml.size_limits)) {
public DevicePaddings(Context context, int devicePaddingId) {
try (XmlResourceParser parser = context.getResources().getXml(devicePaddingId)) {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
@@ -94,16 +94,27 @@ public class DevicePaddings {
if (workspaceTopPadding == null
|| workspaceBottomPadding == null
|| hotseatBottomPadding == null) {
throw new RuntimeException("DevicePadding missing padding.");
if (Utilities.IS_DEBUG_DEVICE) {
throw new RuntimeException("DevicePadding missing padding.");
}
}
mDevicePaddings.add(new DevicePadding(maxWidthPx, workspaceTopPadding,
workspaceBottomPadding, hotseatBottomPadding));
DevicePadding dp = new DevicePadding(maxWidthPx, workspaceTopPadding,
workspaceBottomPadding, hotseatBottomPadding);
if (dp.isValid()) {
mDevicePaddings.add(dp);
} else {
Log.e(TAG, "Invalid device padding found.");
if (Utilities.IS_DEBUG_DEVICE) {
throw new RuntimeException("DevicePadding is invalid");
}
}
}
}
}
}
} catch (IOException | XmlPullParserException e) {
Log.e(TAG, "Failure parsing device padding layout.", e);
throw new RuntimeException(e);
}
@@ -128,6 +139,9 @@ public class DevicePaddings {
*/
public static final class DevicePadding {
// One for each padding since they can each be off by 1 due to rounding errors.
private static final int ROUNDING_THRESHOLD_PX = 3;
private final int maxEmptySpacePx;
private final PaddingFormula workspaceTopPadding;
private final PaddingFormula workspaceBottomPadding;
@@ -143,6 +157,10 @@ public class DevicePaddings {
this.hotseatBottomPadding = hotseatBottomPadding;
}
public int getMaxEmptySpacePx() {
return maxEmptySpacePx;
}
public int getWorkspaceTopPadding(int extraSpacePx) {
return workspaceTopPadding.calculate(extraSpacePx);
}
@@ -154,6 +172,22 @@ public class DevicePaddings {
public int getHotseatBottomPadding(int extraSpacePx) {
return hotseatBottomPadding.calculate(extraSpacePx);
}
public boolean isValid() {
int workspaceTopPadding = getWorkspaceTopPadding(maxEmptySpacePx);
int workspaceBottomPadding = getWorkspaceBottomPadding(maxEmptySpacePx);
int hotseatBottomPadding = getHotseatBottomPadding(maxEmptySpacePx);
int sum = workspaceTopPadding + workspaceBottomPadding + hotseatBottomPadding;
int diff = Math.abs(sum - maxEmptySpacePx);
if (DEBUG) {
Log.d(TAG, "isValid: workspaceTopPadding=" + workspaceTopPadding
+ ", workspaceBottomPadding=" + workspaceBottomPadding
+ ", hotseatBottomPadding=" + hotseatBottomPadding
+ ", sum=" + sum
+ ", diff=" + diff);
}
return diff <= ROUNDING_THRESHOLD_PX;
}
}
/**
+34 -5
View File
@@ -104,6 +104,7 @@ public class DeviceProfile {
private final int mWorkspacePageIndicatorOverlapWorkspace;
// Workspace icons
public float iconScale;
public int iconSizePx;
public int iconTextSizePx;
public int iconDrawablePaddingPx;
@@ -151,6 +152,11 @@ public class DeviceProfile {
public int allAppsIconDrawablePaddingPx;
public float allAppsIconTextSizePx;
// Overview
public int overviewTaskMarginPx;
public int overviewTaskIconSizePx;
public int overviewTaskThumbnailTopMarginPx;
// Widgets
public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
@@ -297,15 +303,29 @@ public class DeviceProfile {
: (hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx
+ (isScalableGrid ? 0 : hotseatExtraVerticalSize)));
overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
overviewTaskIconSizePx =
isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get() ? res.getDimensionPixelSize(
R.dimen.task_thumbnail_icon_size_grid) : res.getDimensionPixelSize(
R.dimen.task_thumbnail_icon_size);
overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2;
// Calculate all of the remaining variables.
extraSpace = updateAvailableDimensions(res);
// Now that we have all of the variables calculated, we can tune certain sizes.
if (isScalableGrid) {
DevicePadding padding = inv.devicePaddings.getDevicePadding(extraSpace);
workspaceTopPadding = padding.getWorkspaceTopPadding(extraSpace);
workspaceBottomPadding = padding.getWorkspaceBottomPadding(extraSpace);
if (isScalableGrid && inv.devicePaddings != null) {
// Paddings were created assuming no scaling, so we first unscale the extra space.
int unscaledExtraSpace = (int) (extraSpace / iconScale);
DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace);
int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace);
int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace);
int paddingHotseatBottom = padding.getHotseatBottomPadding(unscaledExtraSpace);
workspaceTopPadding = Math.round(paddingWorkspaceTop * iconScale);
workspaceBottomPadding = Math.round(paddingWorkspaceBottom * iconScale);
extraHotseatBottomPadding = Math.round(paddingHotseatBottom * iconScale);
extraHotseatBottomPadding = padding.getHotseatBottomPadding(extraSpace);
hotseatBarSizePx += extraHotseatBottomPadding;
hotseatBarBottomPaddingPx += extraHotseatBottomPadding;
} else if (!isVerticalBarLayout() && isPhone && isTallDevice) {
@@ -478,6 +498,8 @@ public class DeviceProfile {
* hotseat sizes, workspaceSpringLoadedShrinkFactor, folderIconSizePx, and folderIconOffsetYPx.
*/
public void updateIconSize(float scale, Resources res) {
iconScale = scale;
// Workspace
final boolean isVerticalLayout = isVerticalBarLayout();
float invIconSizeDp = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize;
@@ -878,7 +900,14 @@ public class DeviceProfile {
writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right));
writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom));
writer.println(prefix + pxToDpStr("scaleToFit", iconScale));
writer.println(prefix + pxToDpStr("extraSpace", extraSpace));
if (inv.devicePaddings != null) {
int unscaledExtraSpace = (int) (extraSpace / iconScale);
writer.println(prefix + pxToDpStr("maxEmptySpace",
inv.devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx()));
}
writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding));
writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding));
writer.println(prefix + pxToDpStr("extraHotseatBottomPadding", extraHotseatBottomPadding));
@@ -28,6 +28,7 @@ import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -61,6 +62,8 @@ public class FastBitmapDrawable extends Drawable {
private boolean mIsPressed;
private boolean mIsDisabled;
private float mDisabledAlpha = 1f;
private float mRoundedCornersRadius = 0f;
private final Path mClipPath = new Path();
// Animator and properties for the fast bitmap drawable's scale
private static final Property<FastBitmapDrawable, Float> SCALE
@@ -102,6 +105,13 @@ public class FastBitmapDrawable extends Drawable {
@Override
public final void draw(Canvas canvas) {
if (mRoundedCornersRadius > 0) {
float radius = mRoundedCornersRadius * mScale;
mClipPath.reset();
mClipPath.addRoundRect(0, 0, getIntrinsicWidth(), getIntrinsicHeight(),
radius, radius, Path.Direction.CCW);
canvas.clipPath(mClipPath);
}
if (mScale != 1f) {
int count = canvas.save();
Rect bounds = getBounds();
@@ -164,6 +174,14 @@ public class FastBitmapDrawable extends Drawable {
return mScale;
}
public void setRoundedCornersRadius(float radius) {
mRoundedCornersRadius = radius;
}
public float getRoundedCornersRadius() {
return mRoundedCornersRadius;
}
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
@@ -132,6 +132,7 @@ public class InvariantDeviceProfile {
* Do not query directly. see {@link DeviceProfile#isScalableGrid}.
*/
protected boolean isScalable;
public int devicePaddingId;
public String dbFile;
public int defaultLayoutId;
@@ -140,7 +141,7 @@ public class InvariantDeviceProfile {
public DeviceProfile landscapeProfile;
public DeviceProfile portraitProfile;
public DevicePaddings devicePaddings;
@Nullable public DevicePaddings devicePaddings;
public Point defaultWallpaperSize;
public Rect defaultWidgetPadding;
@@ -165,6 +166,7 @@ public class InvariantDeviceProfile {
numHotseatIcons = p.numHotseatIcons;
numAllAppsColumns = p.numAllAppsColumns;
isScalable = p.isScalable;
devicePaddingId = p.devicePaddingId;
minCellHeight = p.minCellHeight;
minCellWidth = p.minCellWidth;
borderSpacing = p.borderSpacing;
@@ -225,13 +227,17 @@ public class InvariantDeviceProfile {
.add(myDisplayOption);
result.iconSize = defaultDisplayOption.iconSize;
result.landscapeIconSize = defaultDisplayOption.landscapeIconSize;
result.allAppsIconSize = Math.min(
defaultDisplayOption.allAppsIconSize, myDisplayOption.allAppsIconSize);
if (defaultDisplayOption.allAppsIconSize < myDisplayOption.allAppsIconSize) {
result.allAppsIconSize = defaultDisplayOption.allAppsIconSize;
result.numAllAppsColumns = defaultDisplayOption.numAllAppsColumns;
} else {
result.allAppsIconSize = myDisplayOption.allAppsIconSize;
result.numAllAppsColumns = myDisplayOption.numAllAppsColumns;
}
result.minCellHeight = defaultDisplayOption.minCellHeight;
result.minCellWidth = defaultDisplayOption.minCellWidth;
result.borderSpacing = defaultDisplayOption.borderSpacing;
devicePaddings = new DevicePaddings(context);
initGrid(context, myInfo, result);
}
@@ -262,7 +268,6 @@ public class InvariantDeviceProfile {
ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName);
DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions);
devicePaddings = new DevicePaddings(context);
initGrid(context, displayInfo, displayOption);
return displayOption.grid.name;
}
@@ -278,8 +283,8 @@ public class InvariantDeviceProfile {
demoModeLayoutId = closestProfile.demoModeLayoutId;
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
numAllAppsColumns = closestProfile.numAllAppsColumns;
isScalable = closestProfile.isScalable;
devicePaddingId = closestProfile.devicePaddingId;
mExtraAttrs = closestProfile.extraAttrs;
@@ -293,6 +298,7 @@ public class InvariantDeviceProfile {
minCellHeight = displayOption.minCellHeight;
minCellWidth = displayOption.minCellWidth;
borderSpacing = displayOption.borderSpacing;
numAllAppsColumns = Math.round(displayOption.numAllAppsColumns);
if (Utilities.isGridOptionsEnabled(context)) {
allAppsIconSize = displayOption.allAppsIconSize;
@@ -302,6 +308,10 @@ public class InvariantDeviceProfile {
allAppsIconTextSize = iconTextSize;
}
if (devicePaddingId != 0) {
devicePaddings = new DevicePaddings(context, devicePaddingId);
}
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, displayInfo.metrics);
@@ -609,12 +619,12 @@ public class InvariantDeviceProfile {
private final int numHotseatIcons;
private final String dbFile;
private final int numAllAppsColumns;
private final int defaultLayoutId;
private final int demoModeLayoutId;
private final boolean isScalable;
private final int devicePaddingId;
private final SparseArray<TypedValue> extraAttrs;
@@ -636,11 +646,11 @@ public class InvariantDeviceProfile {
R.styleable.GridDisplayOption_numFolderRows, numRows);
numFolderColumns = a.getInt(
R.styleable.GridDisplayOption_numFolderColumns, numColumns);
numAllAppsColumns = a.getInt(
R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
isScalable = a.getBoolean(
R.styleable.GridDisplayOption_isScalable, false);
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, 0);
a.recycle();
@@ -656,6 +666,7 @@ public class InvariantDeviceProfile {
private final float minHeightDps;
private final boolean canBeDefault;
private float numAllAppsColumns;
private float minCellHeight;
private float minCellWidth;
private float borderSpacing;
@@ -676,6 +687,8 @@ public class InvariantDeviceProfile {
minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0);
canBeDefault = a.getBoolean(
R.styleable.ProfileDisplayOption_canBeDefault, false);
numAllAppsColumns = a.getInt(R.styleable.ProfileDisplayOption_numAllAppsColumns,
grid.numColumns);
minCellHeight = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightDps, 0);
minCellWidth = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthDps, 0);
@@ -702,12 +715,14 @@ public class InvariantDeviceProfile {
minWidthDps = 0;
minHeightDps = 0;
canBeDefault = false;
numAllAppsColumns = 0;
minCellHeight = 0;
minCellWidth = 0;
borderSpacing = 0;
}
private DisplayOption multiply(float w) {
numAllAppsColumns *= w;
iconSize *= w;
landscapeIconSize *= w;
allAppsIconSize *= w;
@@ -720,6 +735,7 @@ public class InvariantDeviceProfile {
}
private DisplayOption add(DisplayOption p) {
numAllAppsColumns += p.numAllAppsColumns;
iconSize += p.iconSize;
landscapeIconSize += p.landscapeIconSize;
allAppsIconSize += p.allAppsIconSize;
+7
View File
@@ -2763,6 +2763,13 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
return new float[] {NO_SCALE, NO_OFFSET};
}
/**
* @see LauncherState#getTaskbarScale(Launcher)
*/
public float getNormalTaskbarScale() {
return 1f;
}
public static Launcher getLauncher(Context context) {
return fromContext(context);
}
@@ -176,6 +176,10 @@ public abstract class LauncherState implements BaseState<LauncherState> {
return launcher.getNormalOverviewScaleAndOffset();
}
public float getTaskbarScale(Launcher launcher) {
return launcher.getNormalTaskbarScale();
}
public float getOverviewFullscreenProgress() {
return 0;
}
+15 -8
View File
@@ -1512,17 +1512,16 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
return getDestinationPage(mOrientationHandler.getPrimaryScroll(this));
}
protected int getDestinationPage(int scaledScroll) {
return getPageNearestToCenterOfScreen(scaledScroll);
protected int getDestinationPage(int primaryScroll) {
return getPageNearestToCenterOfScreen(primaryScroll);
}
public int getPageNearestToCenterOfScreen() {
return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this));
}
private int getPageNearestToCenterOfScreen(int scaledScroll) {
int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
int screenCenter = scaledScroll + (pageOrientationSize / 2);
private int getPageNearestToCenterOfScreen(int primaryScroll) {
int screenCenter = getScreenCenter(primaryScroll);
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
int minDistanceFromScreenCenterIndex = -1;
final int childCount = getChildCount();
@@ -1538,18 +1537,26 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
}
private int getDisplacementFromScreenCenter(int childIndex, int screenCenter) {
int childSize = getChildVisibleSize(childIndex);
int childSize = Math.round(getChildVisibleSize(childIndex));
int halfChildSize = (childSize / 2);
int childCenter = getChildOffset(childIndex) + halfChildSize;
return childCenter - screenCenter;
}
protected int getDisplacementFromScreenCenter(int childIndex) {
int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
int screenCenter = mOrientationHandler.getPrimaryScroll(this) + (pageOrientationSize / 2);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int screenCenter = getScreenCenter(primaryScroll);
return getDisplacementFromScreenCenter(childIndex, screenCenter);
}
private int getScreenCenter(int primaryScroll) {
float primaryScale = mOrientationHandler.getPrimaryScale(this);
float primaryPivot = mOrientationHandler.getPrimaryValue(getPivotX(), getPivotY());
int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
return Math.round(primaryScroll + (pageOrientationSize / 2f - primaryPivot) / primaryScale
+ primaryPivot);
}
protected void snapToDestination() {
snapToPage(getDestinationPage(), getPageSnapDuration());
}
@@ -34,7 +34,6 @@ import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
@@ -133,8 +132,7 @@ public class WorkspaceStateTransitionAnimation {
}
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
workspacePageIndicatorAlpha, fadeInterpolator);
@@ -583,10 +583,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
int padding = mHeader.getMaxTranslation();
for (int i = 0; i < mAH.length; i++) {
mAH[i].padding.top = padding;
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mUsingTabs) {
//add extra space between tabs and recycler view
mAH[i].padding.top += mLauncher.getDeviceProfile().edgeMarginPx;
}
mAH[i].applyPadding();
}
}
@@ -23,8 +23,6 @@ import android.util.AttributeSet;
import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
/**
@@ -43,10 +41,6 @@ public class AllAppsPagedView extends PersonalWorkPagedView {
public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
int topPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0
: context.getResources().getDimensionPixelOffset(
R.dimen.all_apps_header_top_padding);
setPadding(0, topPadding, 0, 0);
}
@Override
@@ -106,8 +106,8 @@ public class FloatingHeaderView extends LinearLayout implements
public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mHeaderTopPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0 :
context.getResources().getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
mHeaderTopPadding = context.getResources()
.getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
}
@Override
@@ -125,7 +125,6 @@ public class FloatingHeaderView extends LinearLayout implements
}
}
mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]);
setPadding(0, mHeaderTopPadding, 0, 0);
mAllRows = mFixedRows;
}
@@ -243,9 +242,7 @@ public class FloatingHeaderView extends LinearLayout implements
public int getMaxTranslation() {
if (mMaxTranslation == 0 && mTabsHidden) {
int paddingOffset = getResources().getDimensionPixelSize(
R.dimen.all_apps_search_bar_bottom_padding);
return FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0 : paddingOffset;
return getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_bottom_padding);
} else if (mMaxTranslation > 0 && mTabsHidden) {
return mMaxTranslation + getPaddingTop();
} else {
@@ -77,6 +77,9 @@ public class Interpolators {
public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL =
v -> ACCEL_DEACCEL.getInterpolation(TOUCH_RESPONSE_INTERPOLATOR.getInterpolation(v));
/**
* Inversion of ZOOM_OUT, compounded with an ease-out.
@@ -38,7 +38,6 @@ public class StateAnimationConfig {
PLAY_ATOMIC_OVERVIEW_PEEK,
SKIP_OVERVIEW,
SKIP_DEPTH_CONTROLLER,
SKIP_TASKBAR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationFlags {}
@@ -47,7 +46,6 @@ public class StateAnimationConfig {
public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
public static final int SKIP_OVERVIEW = 1 << 3;
public static final int SKIP_DEPTH_CONTROLLER = 1 << 4;
public static final int SKIP_TASKBAR = 1 << 5;
public long duration;
public boolean userControlled;
@@ -74,8 +72,6 @@ public class StateAnimationConfig {
ANIM_OVERVIEW_MODAL,
ANIM_DEPTH,
ANIM_OVERVIEW_ACTIONS_FADE,
ANIM_TASKBAR_FADE,
ANIM_HOTSEAT_FADE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
@@ -95,10 +91,8 @@ public class StateAnimationConfig {
public static final int ANIM_OVERVIEW_MODAL = 13;
public static final int ANIM_DEPTH = 14;
public static final int ANIM_OVERVIEW_ACTIONS_FADE = 15;
public static final int ANIM_TASKBAR_FADE = 16;
public static final int ANIM_HOTSEAT_FADE = 17; // if not set, falls back to ANIM_WORKSPACE_FADE
private static final int ANIM_TYPES_COUNT = 18;
private static final int ANIM_TYPES_COUNT = 16;
protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
@@ -136,7 +136,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
}
@Override
public int getClearAllScrollOffset(View view, boolean isRtl) {
public int getClearAllSidePadding(View view, boolean isRtl) {
return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2;
}
@@ -66,7 +66,7 @@ public interface PagedOrientationHandler {
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
int getMeasuredSize(View view);
float getPrimarySize(RectF rect);
int getClearAllScrollOffset(View view, boolean isRtl);
int getClearAllSidePadding(View view, boolean isRtl);
int getSecondaryDimension(View view);
FloatProperty<View> getPrimaryViewTranslate();
FloatProperty<View> getSecondaryViewTranslate();
@@ -132,7 +132,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
}
@Override
public int getClearAllScrollOffset(View view, boolean isRtl) {
public int getClearAllSidePadding(View view, boolean isRtl) {
return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2;
}
@@ -42,43 +42,16 @@ public class MultiValueAlpha {
}
};
/**
* Determines how each alpha should factor into the final alpha.
*/
public enum Mode {
BLEND() {
@Override
public float calculateNewAlpha(float currentAlpha, float otherAlpha) {
return currentAlpha * otherAlpha;
}
},
MAX() {
@Override
public float calculateNewAlpha(float currentAlpha, float otherAlpha) {
return Math.max(currentAlpha, otherAlpha);
}
};
protected abstract float calculateNewAlpha(float currentAlpha, float otherAlpha);
}
private final View mView;
private final AlphaProperty[] mMyProperties;
private final Mode mMode;
private int mValidMask;
// Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values.
private boolean mUpdateVisibility;
public MultiValueAlpha(View view, int size) {
this(view, size, Mode.BLEND);
}
public MultiValueAlpha(View view, int size, Mode mode) {
mView = view;
mMyProperties = new AlphaProperty[size];
mMode = mode;
mValidMask = 0;
for (int i = 0; i < size; i++) {
@@ -124,7 +97,7 @@ public class MultiValueAlpha {
mOthers = 1;
for (AlphaProperty prop : mMyProperties) {
if (prop != this) {
mOthers = mMode.calculateNewAlpha(mOthers, prop.mValue);
mOthers *= prop.mValue;
}
}
}
@@ -134,7 +107,7 @@ public class MultiValueAlpha {
mValidMask = mMyMask;
mValue = value;
mView.setAlpha(mMode.calculateNewAlpha(mOthers, mValue));
mView.setAlpha(mOthers * mValue);
if (mUpdateVisibility) {
AlphaUpdateListener.updateVisibility(mView);
}
@@ -497,12 +497,13 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
@UiThread
private void enforceRoundedCorners() {
if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled(this)) {
if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
resetRoundedCorners();
return;
}
View background = RoundedCornerEnforcement.findBackground(this);
if (RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
if (background == null
|| RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
resetRoundedCorners();
return;
}
@@ -139,6 +139,10 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
}
}
public boolean isReconfigurable() {
return configure != null && (getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) != 0;
}
@Override
public final ComponentName getComponent() {
return provider;
@@ -54,10 +54,13 @@ public class PendingItemDragHelper extends DragPreviewProvider {
@Nullable private RemoteViews mRemoteViewsPreview;
@Nullable private LauncherAppWidgetHostView mAppWidgetHostViewPreview;
private final float mEnforcedRoundedCornersForWidget;
public PendingItemDragHelper(View view) {
super(view);
mAddInfo = (PendingAddItemInfo) view.getTag();
mEnforcedRoundedCornersForWidget = RoundedCornerEnforcement.computeEnforcedRadius(
view.getContext());
}
/**
@@ -115,10 +118,14 @@ public class PendingItemDragHelper extends DragPreviewProvider {
.addDragListener(new AppWidgetHostViewDragListener(launcher));
}
if (preview == null) {
preview = new FastBitmapDrawable(
FastBitmapDrawable p = new FastBitmapDrawable(
app.getWidgetCache().generateWidgetPreview(launcher,
createWidgetInfo.info, maxWidth, null,
previewSizeBeforeScale).first);
if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
p.setRoundedCornersRadius(mEnforcedRoundedCornersForWidget);
}
preview = p;
}
if (previewSizeBeforeScale[0] < previewBitmapWidth) {
@@ -72,12 +72,8 @@ public class RoundedCornerEnforcement {
}
/** Check if the app widget is in the deny list. */
public static boolean isRoundedCornerEnabled(@NonNull View view) {
if (!Utilities.ATLEAST_S || !FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get()) {
return false;
}
// Here we need to test if the view's component is in the (to be created) deny list.
return true;
public static boolean isRoundedCornerEnabled() {
return Utilities.ATLEAST_S && FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get();
}
/**
@@ -94,6 +94,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
protected final BaseActivity mActivity;
protected final DeviceProfile mDeviceProfile;
private final CheckLongPressHelper mLongPressHelper;
private final float mEnforcedCornerRadius;
private RemoteViews mPreview;
private LauncherAppWidgetHostView mAppWidgetHostViewPreview;
@@ -118,6 +119,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
setWillNotDraw(false);
setClipToPadding(false);
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
}
private void setContainerWidth() {
@@ -245,7 +247,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
}
public void applyPreview(Bitmap bitmap) {
applyPreview(new FastBitmapDrawable(bitmap));
FastBitmapDrawable drawable = new FastBitmapDrawable(bitmap);
drawable.setRoundedCornersRadius(mEnforcedCornerRadius);
applyPreview(drawable);
}
private void applyPreview(Drawable drawable) {
@@ -26,6 +26,7 @@ import android.util.IntProperty;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
@@ -152,6 +153,19 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
});
}
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = false;
ScrollView scrollView = findViewById(R.id.widgets_table_scroll_view);
if (getPopupContainer().isEventOverView(scrollView, ev)
&& scrollView.getScrollY() > 0) {
mNoIntercept = true;
}
}
return super.onControllerInterceptTouchEvent(ev);
}
protected WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
.inflate(R.layout.widget_cell, parent, false);
@@ -58,6 +58,7 @@ import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListene
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper;
import com.android.launcher3.widget.util.WidgetsTableUtils;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -71,7 +72,8 @@ import java.util.function.Predicate;
*/
public class WidgetsFullSheet extends BaseWidgetSheet
implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener,
WidgetsSearchBarUIHelper {
private static final String TAG = WidgetsFullSheet.class.getSimpleName();
private static final long DEFAULT_OPEN_DURATION = 267;
@@ -561,6 +563,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet
getWindowInsetsController().hide(WindowInsets.Type.ime());
}
@Override
public void clearSearchBarFocus() {
mSearchAndRecommendationViewHolder.mSearchBar.clearSearchBarFocus();
}
/** A holder class for holding adapters & their corresponding recycler view. */
private final class AdapterHolder {
static final int PRIMARY = 0;
@@ -583,7 +590,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet
apps.getWidgetCache(),
apps.getIconCache(),
/* iconClickListener= */ WidgetsFullSheet.this,
/* iconLongClickListener= */ WidgetsFullSheet.this);
/* iconLongClickListener= */ WidgetsFullSheet.this,
/* WidgetsSearchBarUIHelper= */
mAdapterType == SEARCH ? WidgetsFullSheet.this : null);
mWidgetsListAdapter.setHasStableIds(true);
switch (mAdapterType) {
case PRIMARY:
@@ -41,6 +41,7 @@ import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper;
import java.util.ArrayList;
import java.util.Arrays;
@@ -69,6 +70,7 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
@Nullable private final WidgetsSearchBarUIHelper mSearchBarUIHelper;
private final WidgetsDiffReporter mDiffReporter;
private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
private final WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
@@ -88,7 +90,9 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
OnClickListener iconClickListener, OnLongClickListener iconLongClickListener,
@Nullable WidgetsSearchBarUIHelper searchBarUIHelper) {
mSearchBarUIHelper = searchBarUIHelper;
mDiffReporter = new WidgetsDiffReporter(iconCache, this);
mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(context,
layoutInflater, iconClickListener, iconLongClickListener,
@@ -237,6 +241,9 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
@Override
public void onHeaderClicked(boolean showWidgets, PackageUserKey packageUserKey) {
if (mSearchBarUIHelper != null) {
mSearchBarUIHelper.clearSearchBarFocus();
}
if (showWidgets) {
mWidgetsContentVisiblePackageUserKey = packageUserKey;
updateVisibleEntries();
@@ -79,4 +79,9 @@ public class LauncherWidgetsSearchBar extends LinearLayout implements WidgetsSea
super.onDetachedFromWindow();
mController.onDestroy();
}
@Override
public void clearSearchBarFocus() {
mController.clearFocus();
}
}
@@ -34,6 +34,11 @@ public interface WidgetsSearchBar {
*/
void reset();
/**
* Clears focus from search bar.
*/
void clearSearchBarFocus();
/**
* Sets the vertical location, in pixels, of this search bar relative to its top position.
*/
@@ -103,8 +103,7 @@ public class WidgetsSearchBarController implements TextWatcher,
public void clearSearchResult() {
mSearchAlgorithm.cancel(/* interruptActiveRequests= */ true);
mInput.getText().clear();
mInput.clearFocus();
mInput.hideKeyboard();
clearFocus();
mSearchModeListener.exitSearchMode();
}
@@ -117,18 +116,24 @@ public class WidgetsSearchBarController implements TextWatcher,
@Override
public boolean onBackKey() {
mInput.clearFocus();
mInput.hideKeyboard();
clearFocus();
return true;
}
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
mInput.clearFocus();
mInput.hideKeyboard();
clearFocus();
return true;
}
return false;
}
/**
* Clears focus from edit text.
*/
public void clearFocus() {
mInput.clearFocus();
mInput.hideKeyboard();
}
}
@@ -0,0 +1,27 @@
/*
* 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.widget.picker.search;
/**
* UI helper for {@link WidgetsSearchBar}.
*/
public interface WidgetsSearchBarUIHelper {
/**
* Clears focus from the search bar.
*/
void clearSearchBarFocus();
}