Merge "Prevent setting task thumbnail during swipe to overview" into sc-dev
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 4fd2e40..4e72260 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -116,8 +116,7 @@
android:theme="@style/AppItemActivityTheme"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
- android:exported="true"
- android:label="@string/action_add_to_workspace" >
+ android:exported="true">
<intent-filter>
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
<action android:name="android.content.pm.action.CONFIRM_PIN_APPWIDGET" />
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 6e1aa1e..87649f7 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -18,6 +18,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/taskbar_divider_thickness"
android:layout_height="@dimen/taskbar_divider_height"
- android:layout_marginStart="@dimen/taskbar_icon_spacing"
- android:layout_marginEnd="@dimen/taskbar_icon_spacing"
android:background="@color/taskbar_divider" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_view.xml b/quickstep/res/layout/taskbar_view.xml
new file mode 100644
index 0000000..34a88ea
--- /dev/null
+++ b/quickstep/res/layout/taskbar_view.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<com.android.launcher3.taskbar.TaskbarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/taskbar_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/taskbar_size"
+ android:background="@android:color/transparent"
+ android:layout_gravity="bottom"
+ android:gravity="center"
+ android:visibility="gone" />
+
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index c4becf1..9ab49ce 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -46,6 +46,7 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarController;
import com.android.launcher3.taskbar.TaskbarStateHandler;
+import com.android.launcher3.taskbar.TaskbarView;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DisplayController;
@@ -243,9 +244,10 @@
mTaskbarController = null;
}
if (mDeviceProfile.isTaskbarPresent) {
+ TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView();
TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this);
mTaskbarController = new TaskbarController(this,
- taskbarActivityContext.getTaskbarContainerView());
+ taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome);
mTaskbarController.init();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8312b82..fc5e2c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -54,10 +54,7 @@
return mTaskbarContainerView;
}
- /**
- * @return A LayoutInflater to use in this Context. Views inflated with this LayoutInflater will
- * be able to access this TaskbarActivityContext via ActivityContext.lookupContext().
- */
+ @Override
public LayoutInflater getLayoutInflater() {
return mLayoutInflater;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 528f43e..5202d91 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -84,7 +84,7 @@
private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
return insetsInfo -> {
if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
- || mTaskbarView.isDraggingItem()) {
+ || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) {
// We're invisible or dragging out of taskbar, let touches pass through us.
insetsInfo.touchableRegion.setEmpty();
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index f652961..abf6d54 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -19,8 +19,6 @@
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.AbstractFloatingView.TYPE_HIDE_TASKBAR;
-import static com.android.launcher3.AbstractFloatingView.TYPE_REPLACE_TASKBAR_WITH_HOTSEAT;
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;
@@ -43,7 +41,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
@@ -54,6 +51,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.AnimatedFloat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -70,7 +68,8 @@
private static final String WINDOW_TITLE = "Taskbar";
private final TaskbarContainerView mTaskbarContainerView;
- private final TaskbarView mTaskbarView;
+ private final TaskbarView mTaskbarViewInApp;
+ private final TaskbarView mTaskbarViewOnHome;
private final BaseQuickstepLauncher mLauncher;
private final WindowManager mWindowManager;
// Layout width and height of the Taskbar in the default state.
@@ -91,14 +90,17 @@
private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
+ private boolean mIsAnimatingToApp;
public TaskbarController(BaseQuickstepLauncher launcher,
- TaskbarContainerView taskbarContainerView) {
+ TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) {
mLauncher = launcher;
mTaskbarContainerView = taskbarContainerView;
mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks());
- mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view);
- mTaskbarView.construct(createTaskbarViewCallbacks());
+ mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view);
+ mTaskbarViewInApp.construct(createTaskbarViewCallbacks());
+ mTaskbarViewOnHome = taskbarViewOnHome;
+ mTaskbarViewOnHome.construct(createTaskbarViewCallbacks());
mWindowManager = mLauncher.getWindowManager();
mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize);
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
@@ -115,12 +117,13 @@
return new TaskbarVisibilityControllerCallbacks() {
@Override
public void updateTaskbarBackgroundAlpha(float alpha) {
- mTaskbarView.setBackgroundAlpha(alpha);
+ mTaskbarViewInApp.setBackgroundAlpha(alpha);
}
@Override
public void updateTaskbarVisibilityAlpha(float alpha) {
mTaskbarContainerView.setAlpha(alpha);
+ mTaskbarViewOnHome.setAlpha(alpha);
}
};
}
@@ -196,7 +199,7 @@
public View.OnLongClickListener getItemOnLongClickListener() {
return view -> {
if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
- alignRealHotseatWithTaskbar();
+ // TODO: remove this path
return mDragController.startWorkspaceDragOnLongClick(view);
} else {
return mDragController.startSystemDragOnLongClick(view);
@@ -205,11 +208,24 @@
}
@Override
- public int getEmptyHotseatViewVisibility() {
+ public int getEmptyHotseatViewVisibility(TaskbarView taskbarView) {
// When on the home screen, we want the empty hotseat views to take up their full
// space so that the others line up with the home screen hotseat.
- return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
- ? View.INVISIBLE : View.GONE;
+ boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome
+ || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher;
+ return isOnHomeScreen ? View.INVISIBLE : View.GONE;
+ }
+
+ @Override
+ public float getNonIconScale(TaskbarView taskbarView) {
+ return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f;
+ }
+
+ @Override
+ public void onItemPositionsChanged(TaskbarView taskbarView) {
+ if (taskbarView == mTaskbarViewOnHome) {
+ alignRealHotseatWithTaskbar();
+ }
}
};
}
@@ -218,7 +234,7 @@
return new TaskbarHotseatControllerCallbacks() {
@Override
public void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
- mTaskbarView.updateHotseatItems(hotseatItemInfos);
+ mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos);
mLatestLoadedHotseatItems = hotseatItemInfos;
dedupeAndUpdateRecentItems();
}
@@ -235,7 +251,8 @@
@Override
public void updateRecentTaskAtIndex(int taskIndex, Task task) {
- mTaskbarView.updateRecentTaskAtIndex(taskIndex, task);
+ mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task);
+ mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task);
}
};
}
@@ -244,16 +261,20 @@
* Initializes the Taskbar, including adding it to the screen.
*/
public void init() {
- mTaskbarView.init(mHotseatController.getNumHotseatIcons(),
+ mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(),
mRecentsController.getNumRecentIcons());
- mTaskbarContainerView.init(mTaskbarView);
+ mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(),
+ mRecentsController.getNumRecentIcons());
+ mTaskbarContainerView.init(mTaskbarViewInApp);
addToWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
mTaskbarVisibilityController.init();
mHotseatController.init();
mRecentsController.init();
- SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f);
+ SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed()
+ ? getTaskbarScaleOnHome() : 1f);
+ updateWhichTaskbarViewIsVisible();
}
private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
@@ -274,7 +295,8 @@
mAnimator.end();
}
- mTaskbarView.cleanup();
+ mTaskbarViewInApp.cleanup();
+ mTaskbarViewOnHome.cleanup();
mTaskbarContainerView.cleanup();
removeFromWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(null);
@@ -313,7 +335,7 @@
TaskbarContainerView.LayoutParams taskbarLayoutParams =
new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y);
taskbarLayoutParams.gravity = gravity;
- mTaskbarView.setLayoutParams(taskbarLayoutParams);
+ mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams);
mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams);
}
@@ -330,7 +352,6 @@
mAnimator = createAnimToLauncher(null, duration);
} else {
mAnimator = createAnimToApp(duration);
- replaceTaskbarWithHotseatOrViceVersa();
}
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -351,36 +372,41 @@
if (toState != null) {
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
}
- anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(),
+ anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(),
getTaskbarScaleOnHome(), LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mIsAnimatingToLauncher = true;
- mTaskbarView.updateHotseatItemsVisibility();
+ mTaskbarViewInApp.updateHotseatItemsVisibility();
}
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimatingToLauncher = false;
+ updateWhichTaskbarViewIsVisible();
}
});
- anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar);
-
return anim.buildAnim();
}
private Animator createAnimToApp(long duration) {
PendingAnimation anim = new PendingAnimation(duration);
anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration));
- anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR);
+ anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mTaskbarView.updateHotseatItemsVisibility();
- setReplaceTaskbarWithHotseat(false);
+ mIsAnimatingToApp = true;
+ mTaskbarViewInApp.updateHotseatItemsVisibility();
+ updateWhichTaskbarViewIsVisible();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToApp = false;
}
});
return anim.buildAnim();
@@ -405,11 +431,11 @@
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
- return mTaskbarView.isEventOverAnyItem(ev);
+ return mTaskbarViewInApp.isEventOverAnyItem(ev);
}
public boolean isDraggingItem() {
- return mTaskbarView.isDraggingItem();
+ return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem();
}
private void dedupeAndUpdateRecentItems() {
@@ -454,7 +480,8 @@
tasksArray[tasksArray.length - 1 - i] = task;
}
- mTaskbarView.updateRecentTasks(tasksArray);
+ mTaskbarViewInApp.updateRecentTasks(tasksArray);
+ mTaskbarViewOnHome.updateRecentTasks(tasksArray);
mRecentsController.loadIconsForTasks(tasksArray);
}
@@ -475,10 +502,11 @@
int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize;
int hotseatTopDiff = hotseatHeight - grid.taskbarSize;
- mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds);
- mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff,
- mTaskbarView.getWidth() - hotseatBounds.right,
- mTaskbarView.getHeight() - hotseatBounds.bottom);
+ mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds);
+ mLauncher.getHotseat().setPadding(hotseatBounds.left,
+ hotseatBounds.top + hotseatTopDiff,
+ mTaskbarViewOnHome.getWidth() - hotseatBounds.right,
+ mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
}
/**
@@ -486,36 +514,32 @@
* show the real one instead.
*/
public void onLauncherDragLayerHierarchyChanged() {
- replaceTaskbarWithHotseatOrViceVersa();
+ // TODO: remove, as this is a no-op now
}
- private void replaceTaskbarWithHotseatOrViceVersa() {
- boolean replaceTaskbarWithHotseat = AbstractFloatingView.getTopOpenViewWithType(mLauncher,
- TYPE_REPLACE_TASKBAR_WITH_HOTSEAT) != null;
- if (!mLauncher.hasBeenResumed()) {
- replaceTaskbarWithHotseat = false;
- }
- setReplaceTaskbarWithHotseat(replaceTaskbarWithHotseat);
-
- boolean hideTaskbar = AbstractFloatingView.getTopOpenViewWithType(mLauncher,
- TYPE_HIDE_TASKBAR) != null;
- mTaskbarVisibilityController.animateToVisibilityForFloatingView(hideTaskbar ? 0f : 1f);
- }
-
- private void setReplaceTaskbarWithHotseat(boolean replaceTaskbarWithHotseat) {
- Hotseat hotseat = mLauncher.getHotseat();
- if (replaceTaskbarWithHotseat) {
- alignRealHotseatWithTaskbar();
- hotseat.getReplaceTaskbarAlpha().setValue(1f);
- mTaskbarView.setHotseatViewsHidden(true);
+ private void updateWhichTaskbarViewIsVisible() {
+ boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
+ || mIsAnimatingToApp;
+ if (isInApp) {
+ mTaskbarViewInApp.setVisibility(View.VISIBLE);
+ mTaskbarViewOnHome.setVisibility(View.INVISIBLE);
+ mLauncher.getHotseat().setIconsAlpha(0);
} else {
- hotseat.getReplaceTaskbarAlpha().setValue(0f);
- mTaskbarView.setHotseatViewsHidden(false);
+ mTaskbarViewInApp.setVisibility(View.INVISIBLE);
+ mTaskbarViewOnHome.setVisibility(View.VISIBLE);
+ mLauncher.getHotseat().setIconsAlpha(1);
}
}
- private float getTaskbarScaleOnHome() {
- return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale();
+ /**
+ * Returns the ratio of the taskbar icon size on home vs in an app.
+ */
+ public float getTaskbarScaleOnHome() {
+ DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext()
+ .getDeviceProfile();
+ DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext())
+ .getDeviceProfile();
+ return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx;
}
/**
@@ -561,7 +585,10 @@
protected interface TaskbarViewCallbacks {
View.OnClickListener getItemOnClickListener();
View.OnLongClickListener getItemOnLongClickListener();
- int getEmptyHotseatViewVisibility();
+ int getEmptyHotseatViewVisibility(TaskbarView taskbarView);
+ /** Returns how much to scale non-icon elements such as spacing and dividers. */
+ float getNonIconScale(TaskbarView taskbarView);
+ void onItemPositionsChanged(TaskbarView taskbarView);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 1d762e9..3567c17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,11 +15,14 @@
*/
package com.android.launcher3.taskbar;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Matrix;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -36,6 +39,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
@@ -48,20 +52,23 @@
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
-public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent {
+public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable {
private final ColorDrawable mBackgroundDrawable;
- private final int mItemMarginLeftRight;
+ private final int mDividerWidth;
+ private final int mDividerHeight;
private final int mIconTouchSize;
private final boolean mIsRtl;
private final int mTouchSlop;
private final RectF mTempDelegateBounds = new RectF();
private final RectF mDelegateSlopBounds = new RectF();
private final int[] mTempOutLocation = new int[2];
- private final Matrix mTempMatrix = new Matrix();
// Initialized in TaskbarController constructor.
private TaskbarController.TaskbarViewCallbacks mControllerCallbacks;
+ // Scale on elements that aren't icons.
+ private float mNonIconScale;
+ private int mItemMarginLeftRight;
// Initialized in init().
private LayoutTransition mLayoutTransition;
@@ -78,7 +85,6 @@
private boolean mIsDraggingItem;
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
- private boolean mIsHotseatHidden;
public TaskbarView(@NonNull Context context) {
this(context, null);
@@ -99,7 +105,8 @@
Resources resources = getResources();
mBackgroundDrawable = (ColorDrawable) getBackground();
- mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness);
+ mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height);
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
mIsRtl = Utilities.isRtl(resources);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -107,11 +114,16 @@
protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks) {
mControllerCallbacks = taskbarViewCallbacks;
+ mNonIconScale = mControllerCallbacks.getNonIconScale(this);
+ mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale);
}
protected void init(int numHotseatIcons, int numRecentIcons) {
mLayoutTransition = new LayoutTransition();
- setLayoutTransitionsEnabled(true);
+ addUpdateListenerForAllLayoutTransitions(
+ () -> mControllerCallbacks.onItemPositionsChanged(this));
+ setLayoutTransition(mLayoutTransition);
mHotseatStartIndex = 0;
mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1;
@@ -125,12 +137,30 @@
updateRecentTasks(new Task[numRecentIcons]);
}
- private void setLayoutTransitionsEnabled(boolean enabled) {
- setLayoutTransition(enabled ? mLayoutTransition : null);
+ private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) {
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_APPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_DISAPPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.APPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.DISAPPEARING, onUpdate);
+ }
+
+ private void addUpdateListenerForLayoutTransition(int transitionType, Runnable onUpdate) {
+ Animator anim = mLayoutTransition.getAnimator(transitionType);
+ if (anim instanceof ValueAnimator) {
+ ((ValueAnimator) anim).addUpdateListener(valueAnimator -> onUpdate.run());
+ } else {
+ AnimatorSet animSet = new AnimatorSet();
+ ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1);
+ updateAnim.addUpdateListener(valueAnimator -> onUpdate.run());
+ animSet.playTogether(anim, updateAnim);
+ mLayoutTransition.setAnimator(transitionType, animSet);
+ }
}
protected void cleanup() {
removeAllViews();
+ mHotseatRecentsDivider = null;
}
/**
@@ -170,12 +200,11 @@
if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId
|| needsReinflate) {
removeView(hotseatView);
- TaskbarActivityContext activityContext =
- ActivityContext.lookupContext(getContext());
+ ActivityContext activityContext = ActivityContext.lookupContext(getContext());
if (isFolder) {
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
- activityContext, this, folderInfo);
+ ActivityContext.lookupContext(getContext()), this, folderInfo);
folderIcon.setTextVisible(false);
hotseatView = folderIcon;
} else {
@@ -216,22 +245,12 @@
}
}
- /**
- * Hides or shows the hotseat items immediately (without layout transitions).
- */
- protected void setHotseatViewsHidden(boolean hidden) {
- mIsHotseatHidden = hidden;
- setLayoutTransitionsEnabled(false);
- updateHotseatItemsVisibility();
- setLayoutTransitionsEnabled(true);
- }
-
private void updateHotseatItemVisibility(View hotseatView) {
if (hotseatView.getTag() != null) {
- hotseatView.setVisibility(mIsHotseatHidden ? INVISIBLE : VISIBLE);
+ hotseatView.setVisibility(VISIBLE);
} else {
int oldVisibility = hotseatView.getVisibility();
- int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility();
+ int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this);
hotseatView.setVisibility(newVisibility);
if (oldVisibility == GONE && newVisibility != GONE) {
// By default, the layout transition only runs when going to VISIBLE,
@@ -243,7 +262,11 @@
private View addDivider(int dividerIndex) {
View divider = inflate(R.layout.taskbar_divider);
- addView(divider, dividerIndex);
+ LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight);
+ lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
+ divider.setScaleX(mNonIconScale);
+ divider.setScaleY(mNonIconScale);
+ addView(divider, dividerIndex, lp);
return divider;
}
@@ -437,9 +460,9 @@
}
/**
- * @return The bounding box of where the hotseat elements will be when we reach the given scale.
+ * @return The bounding box of where the hotseat elements are relative to this TaskbarView.
*/
- protected RectF getHotseatBoundsAtScale(float taskbarViewScale) {
+ protected RectF getHotseatBounds() {
View firstHotseatView = null, lastHotseatView = null;
for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
View child = getChildAt(i);
@@ -455,14 +478,11 @@
}
View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView;
View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView;
- RectF hotseatBounds = new RectF(
+ return new RectF(
leftmostHotseatView.getLeft() - mItemMarginLeftRight,
leftmostHotseatView.getTop(),
rightmostHotseatView.getRight() + mItemMarginLeftRight,
rightmostHotseatView.getBottom());
- mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY());
- mTempMatrix.mapRect(hotseatBounds);
- return hotseatBounds;
}
// FolderIconParent implemented methods.
@@ -493,7 +513,12 @@
}
private View inflate(@LayoutRes int layoutResId) {
- TaskbarActivityContext taskbarActivityContext = ActivityContext.lookupContext(getContext());
- return taskbarActivityContext.getLayoutInflater().inflate(layoutResId, this, false);
+ return ActivityContext.lookupContext(getContext()).getLayoutInflater()
+ .inflate(layoutResId, this, false);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ // Ignore, we just implement Insettable to draw behind system insets.
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index fb58bf6..aa770d2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -82,20 +82,6 @@
}
@Override
- public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
- if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
- // Translate hotseat offscreen if we show it in overview.
- RecentsView recentsView = launcher.getOverviewPanel();
- ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
- scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
- launcher.getDeviceProfile(),
- recentsView.getPagedOrientationHandler());
- return scaleAndTranslation;
- }
- return super.getHotseatScaleAndTranslation(launcher);
- }
-
- @Override
protected float getDepthUnchecked(Context context) {
return 1f;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 5a28cfd..d8a5f9b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -78,40 +78,11 @@
}
@Override
- public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
- if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
- DeviceProfile dp = launcher.getDeviceProfile();
- if (dp.allAppsIconSizePx >= dp.iconSizePx) {
- return new ScaleAndTranslation(1, 0, 0);
- } else {
- float scale = ((float) dp.allAppsIconSizePx) / dp.iconSizePx;
- // Distance between the screen center (which is the pivotY for hotseat) and the
- // bottom of the hotseat (which we want to preserve)
- float distanceFromBottom = dp.heightPx / 2 - dp.hotseatBarBottomPaddingPx;
- // On scaling, the bottom edge is moved closer to the pivotY. We move the
- // hotseat back down so that the bottom edge's position is preserved.
- float translationY = distanceFromBottom * (1 - scale);
- return new ScaleAndTranslation(scale, 0, translationY);
- }
- }
- return getWorkspaceScaleAndTranslation(launcher);
- }
-
- @Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, NO_OFFSET};
}
@Override
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- if (this == OVERVIEW) {
- // Treat the QSB as part of the hotseat so they move together.
- return getHotseatScaleAndTranslation(launcher);
- }
- return super.getQsbScaleAndTranslation(launcher);
- }
-
- @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index ae644cd..3faf72a 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -112,20 +112,32 @@
}
// Set up springs for the hotseat and qsb.
- ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0);
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
if (grid.isVerticalBarLayout()) {
- for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatChild.getChildAt(i);
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
}
} else {
- for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatChild.getChildAt(i);
- addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
+ final int hotseatRow, qsbRow, taskbarRow;
+ if (grid.isTaskbarPresent) {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 2;
+ } else {
+ hotseatRow = grid.inv.numRows + 1;
+ qsbRow = grid.inv.numRows + 2;
+ }
+ // Taskbar and hotseat overlap.
+ taskbarRow = hotseatRow;
+
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
+ addStaggeredAnimationForView(child, hotseatRow, totalRows);
}
- addStaggeredAnimationForView(hotseat.getQsb(), grid.inv.numRows + 2, totalRows);
+ addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows);
+ addStaggeredAnimationForView(hotseat.getTaskbarView(), taskbarRow, totalRows);
}
if (animateOverviewScrim) {
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
new file mode 100644
index 0000000..04bde8f
--- /dev/null
+++ b/res/drawable/add_item_dialog_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+ <solid android:color="?android:attr/colorBackground" />
+ <corners
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/add_item_dialog_button_background.xml b/res/drawable/add_item_dialog_button_background.xml
new file mode 100644
index 0000000..1b4591f
--- /dev/null
+++ b/res/drawable/add_item_dialog_button_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset
+ android:insetLeft="@dimen/pin_widget_button_inset_horizontal"
+ android:insetRight="@dimen/pin_widget_button_inset_horizontal"
+ android:insetTop="@dimen/pin_widget_button_inset_vertical"
+ android:insetBottom="@dimen/pin_widget_button_inset_vertical"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:tint="?android:attr/colorAccent" android:shape="rectangle">
+ <corners android:radius="18dp" />
+ <solid android:color="#FFFFFF" />
+ <padding
+ android:left="@dimen/pin_widget_button_padding_horizontal"
+ android:top="@dimen/pin_widget_button_padding_vertical"
+ android:right="@dimen/pin_widget_button_padding_horizontal"
+ android:bottom="@dimen/pin_widget_button_padding_vertical" />
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index b1a1efe..d5e7333 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -17,70 +17,51 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/add_item_confirmation"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:padding="24dp"
android:orientation="vertical">
- <ScrollView
+
+ <TextView
+ style="@style/TextHeadline"
+ android:id="@+id/widget_appName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="24sp"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:maxLines="1" />
+
+ <include layout="@layout/widget_cell"
+ android:id="@+id/widget_cell"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:clipToPadding="false">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="20dp"
- android:paddingLeft="24dp"
- android:paddingRight="24dp"
- android:paddingTop="4dp"
- android:text="@string/add_item_request_drag_hint" />
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorPrimaryDark"
- android:theme="?attr/widgetsTheme">
-
- <com.android.launcher3.widget.WidgetCell
- android:id="@+id/widget_cell"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_weight="1"
- android:background="?android:attr/colorPrimaryDark"
- android:focusable="true"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
-
- <include layout="@layout/widget_cell_content" />
-
- </com.android.launcher3.widget.WidgetCell>
- </FrameLayout>
- </LinearLayout>
- </ScrollView>
+ android:layout_marginVertical="16dp" />
<LinearLayout
- style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
- android:paddingBottom="4dp"
- android:paddingEnd="12dp"
- android:paddingStart="12dp"
- android:paddingTop="4dp" >
+ android:padding="8dp"
+ android:orientation="horizontal">
<Button
- style="?android:attr/buttonBarButtonStyle"
+ style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onCancelClick"
android:text="@android:string/cancel" />
+
+ <Space
+ android:layout_width="4dp"
+ android:layout_height="wrap_content" />
+
<Button
- style="?android:attr/buttonBarButtonStyle"
+ style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onPlaceAutomaticallyClick"
diff --git a/res/layout/app_widget_resize_frame.xml b/res/layout/app_widget_resize_frame.xml
index 2e476df..671dbc6 100644
--- a/res/layout/app_widget_resize_frame.xml
+++ b/res/layout/app_widget_resize_frame.xml
@@ -26,6 +26,7 @@
<!-- Frame -->
<ImageView
+ android:id="@+id/widget_resize_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index d6b4a37..0d11b50 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -32,6 +32,8 @@
android:paddingEnd="@dimen/popup_padding_end"
android:drawableEnd="@drawable/ic_drag_handle"
android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textSize="14sp"
android:textColor="?android:attr/textColorPrimary"
launcher:layoutHorizontal="true"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 68251e4..9f45f30 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -31,7 +31,8 @@
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
android:paddingEnd="@dimen/popup_padding_end"
android:textSize="14sp"
- android:maxLines="1"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
launcher:iconDisplay="shortcut_popup"
launcher:layoutHorizontal="true"
diff --git a/res/layout/taskbar_view.xml b/res/layout/taskbar_view.xml
new file mode 100644
index 0000000..96ae43d
--- /dev/null
+++ b/res/layout/taskbar_view.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<Space
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:visibility="gone" />
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index a3d0070..30bd8b1 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -18,8 +18,8 @@
android:layout_height="wrap_content">
<!-- The image of the widget. This view does not support padding. Any placement adjustment
- should be done using margins.
- width & height are set at runtime after scaling the preview image. -->
+ should be done using margins. Width & height are set at runtime after scaling the preview
+ image. -->
<com.android.launcher3.widget.WidgetImageView
android:id="@+id/widget_preview"
android:layout_width="0dp"
@@ -41,16 +41,15 @@
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/widget_cell_font_size" />
- <!-- The original dimensions of the widget (can't be the same text as above due to different
- style. -->
+ <!-- The original dimensions of the widget -->
<TextView
android:id="@+id/widget_dims"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/widget_cell_font_size"
- android:alpha="0.8" />
+ android:alpha="0.7" />
<TextView
android:id="@+id/widget_description"
@@ -58,9 +57,10 @@
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="@dimen/widget_cell_font_size"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
android:maxLines="2"
android:ellipsize="end"
- android:fadingEdge="horizontal" />
+ android:fadingEdge="horizontal"
+ android:alpha="0.7" />
</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 916ff1b..a9d523a 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -29,16 +29,6 @@
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"/>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:paddingTop="4dp"
- android:fontFamily="sans-serif"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="14sp"
- android:text="@string/long_press_widget_to_add"/>
-
<ScrollView
android:id="@+id/widgets_table_scroll_view"
android:layout_width="match_parent"
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index ed3a042..598041c 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -56,7 +56,8 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:alpha="0.7"
tools:text="m widgets, n shortcuts" />
</LinearLayout>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 510e1f4..07a5096 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -21,6 +21,8 @@
<style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+ <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
+ <item name="android:windowNoTitle">true</item>
</style>
</resources>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d6c936..cf830c7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -138,6 +138,12 @@
<dimen name="shortcut_preview_padding_right">0dp</dimen>
<dimen name="shortcut_preview_padding_top">0dp</dimen>
+<!-- Pin widget dialog -->
+ <dimen name="pin_widget_button_padding_horizontal">8dp</dimen>
+ <dimen name="pin_widget_button_padding_vertical">4dp</dimen>
+ <dimen name="pin_widget_button_inset_horizontal">4dp</dimen>
+ <dimen name="pin_widget_button_inset_vertical">6dp</dimen>
+
<!-- Dragging -->
<!-- Drag padding to add to the bottom of drop targets -->
<dimen name="drop_target_drag_padding">14dp</dimen>
@@ -185,7 +191,7 @@
<!-- Deep shortcuts -->
<dimen name="deep_shortcuts_elevation">0dp</dimen>
- <dimen name="bg_popup_item_width">234dp</dimen>
+ <dimen name="bg_popup_item_width">216dp</dimen>
<dimen name="bg_popup_item_height">56dp</dimen>
<dimen name="pre_drag_view_scale">6dp</dimen>
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
@@ -277,4 +283,7 @@
<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="taskbar_size">0dp</dimen>
+ <!-- Size of the maximum radius for the enforced rounded rectangles. -->
+ <dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1eb123b..7c372830 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -269,8 +269,6 @@
<string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
<!-- Strings for widgets & more in the popup container/bottom sheet -->
- <!-- Title for a bottom sheet that shows widgets for a particular app -->
- <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> widgets</string>
<!-- Accessibility title for the popup containing a list of widgets. [CHAR_LIMIT=50] -->
<string name="widgets_list">Widgets list</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index adc2238..a27cdac 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -145,6 +145,8 @@
<style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
+ <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
+ <item name="android:windowNoTitle">true</item>
</style>
<style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -281,4 +283,8 @@
<item name="android:colorControlHighlight">#DFE1E5</item>
<item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
</style>
+
+ <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">
+ <item name="android:background">@drawable/add_item_dialog_button_background</item>
+ </style>
</resources>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index d02efb0..ab91785 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -14,12 +14,15 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.SizeF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.widget.ImageView;
import androidx.annotation.Nullable;
@@ -166,6 +169,15 @@
DragLayer dl = launcher.getDragLayer();
AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
.inflate(R.layout.app_widget_resize_frame, dl, false);
+ if (widget.hasEnforcedCornerRadius()) {
+ float enforcedCornerRadius = widget.getEnforcedCornerRadius();
+ ImageView imageView = frame.findViewById(R.id.widget_resize_frame);
+ Drawable d = imageView.getDrawable();
+ if (d instanceof GradientDrawable) {
+ GradientDrawable gd = (GradientDrawable) d.mutate();
+ gd.setCornerRadius(enforcedCornerRadius);
+ }
+ }
frame.setupForWidget(widget, cellLayout, dl);
((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index af4a843..4049ed6 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -29,8 +29,6 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.util.MultiValueAlpha;
-
import java.util.function.Consumer;
/**
@@ -38,10 +36,6 @@
*/
public class Hotseat extends CellLayout implements Insettable {
- private static final int ALPHA_INDEX_STATE = 0;
- private static final int ALPHA_INDEX_REPLACE_TASKBAR = 1;
- private static final int NUM_ALPHA_CHANNELS = 2;
-
// Ratio of empty space, qsb should take up to appear visually centered.
public static final float QSB_CENTER_FACTOR = .325f;
@@ -52,10 +46,12 @@
@Nullable
private Consumer<Boolean> mOnVisibilityAggregatedCallback;
- private final MultiValueAlpha mMultiValueAlpha;
private final View mQsb;
private final int mQsbHeight;
+ private final View mTaskbarView;
+ private final int mTaskbarViewHeight;
+
public Hotseat(Context context) {
this(context, null);
}
@@ -66,12 +62,15 @@
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS, MultiValueAlpha.Mode.MAX);
- mMultiValueAlpha.setUpdateVisibility(true);
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
mQsbHeight = mQsb.getLayoutParams().height;
addView(mQsb);
+
+ mTaskbarView = LayoutInflater.from(context).inflate(R.layout.taskbar_view, this, false);
+ mTaskbarViewHeight = mTaskbarView.getLayoutParams().height;
+ // We want taskbar in the back so its background applies to Hotseat as well.
+ addView(mTaskbarView, 0);
}
/**
@@ -193,6 +192,8 @@
int width = getShortcutsAndWidgets().getMeasuredWidth();
mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY));
+ mTaskbarView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mTaskbarViewHeight, MeasureSpec.EXACTLY));
}
@Override
@@ -212,6 +213,13 @@
- (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom);
int top = bottom - mQsbHeight;
mQsb.layout(left, top, right, bottom);
+
+ int taskbarWidth = mTaskbarView.getMeasuredWidth();
+ left = (r - l - taskbarWidth) / 2;
+ right = left + taskbarWidth;
+ bottom = b - t;
+ top = bottom - mTaskbarViewHeight;
+ mTaskbarView.layout(left, top, right, bottom);
}
/**
@@ -221,12 +229,11 @@
return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator);
}
- public MultiValueAlpha.AlphaProperty getStateAlpha() {
- return mMultiValueAlpha.getProperty(ALPHA_INDEX_STATE);
- }
-
- public MultiValueAlpha.AlphaProperty getReplaceTaskbarAlpha() {
- return mMultiValueAlpha.getProperty(ALPHA_INDEX_REPLACE_TASKBAR);
+ /**
+ * Sets the alpha value of just our ShortcutAndWidgetContainer.
+ */
+ public void setIconsAlpha(float alpha) {
+ getShortcutsAndWidgets().setAlpha(alpha);
}
/**
@@ -235,4 +242,11 @@
public View getQsb() {
return mQsb;
}
+
+ /**
+ * Returns the Taskbar inside hotseat
+ */
+ public View getTaskbarView() {
+ return mTaskbarView;
+ }
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index e9a3495..06bc438 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -176,21 +176,12 @@
return launcher.getNormalOverviewScaleAndOffset();
}
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
- }
-
public float getOverviewFullscreenProgress() {
return 0;
}
public int getVisibleElements(Launcher launcher) {
- DeviceProfile deviceProfile = launcher.getDeviceProfile();
- int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
- if (!deviceProfile.isTaskbarPresent) {
- flags |= HOTSEAT_ICONS;
- }
- return flags;
+ return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
}
/**
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 412754e..6db7a75 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -54,7 +54,6 @@
import com.android.launcher3.graphics.WorkspaceDragScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DynamicResource;
-import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.plugins.ResourceProvider;
/**
@@ -96,7 +95,6 @@
ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
mLauncher);
- ScaleAndTranslation qsbScaleAndTranslation = state.getQsbScaleAndTranslation(mLauncher);
mNewScale = scaleAndTranslation.scale;
PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
@@ -135,8 +133,8 @@
}
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- propertySetter.setFloat(hotseat.getStateAlpha(), MultiValueAlpha.VALUE,
- hotseatIconsAlpha, config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
+ propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
+ config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
workspacePageIndicatorAlpha, fadeInterpolator);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 96251f0..7f76d27 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -215,6 +215,9 @@
public static final BooleanFlag ENABLE_SPLIT_SELECT = getDebugFlag(
"ENABLE_SPLIT_SELECT", false, "Uses new split screen selection overview UI");
+ public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
+ "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 7bc9865..b7a7366 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -37,11 +37,14 @@
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
+import android.view.WindowManager;
+import android.widget.TextView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.InvariantDeviceProfile;
@@ -127,6 +130,9 @@
if (savedInstanceState == null) {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_START);
}
+
+ TextView widgetAppName = findViewById(R.id.widget_appName);
+ widgetAppName.setText(getApplicationInfo().labelRes);
}
@Override
@@ -326,4 +332,15 @@
.withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
.log(command);
}
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ View view = getWindow().getDecorView();
+ WindowManager.LayoutParams layoutParams =
+ (WindowManager.LayoutParams) view.getLayoutParams();
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ getWindowManager().updateViewLayout(view, layoutParams);
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 92ae670..5cd95dc 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -17,8 +17,12 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -28,14 +32,30 @@
private final LauncherAppWidgetHostView mAppWidgetHostView;
private Paint mPaint = new Paint();
+ private final Path mClipPath;
public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
mAppWidgetHostView = appWidgetHostView;
+ Path clipPath = null;
+ if (appWidgetHostView.getClipToOutline()) {
+ Outline outline = new Outline();
+ mAppWidgetHostView.getOutlineProvider().getOutline(mAppWidgetHostView, outline);
+ Rect rect = new Rect();
+ if (outline.getRect(rect)) {
+ float radius = outline.getRadius();
+ clipPath = new Path();
+ clipPath.addRoundRect(new RectF(rect), radius, radius, Path.Direction.CCW);
+ }
+ }
+ mClipPath = clipPath;
}
@Override
public void draw(Canvas canvas) {
int saveCount = canvas.saveLayer(0, 0, getIntrinsicWidth(), getIntrinsicHeight(), mPaint);
+ if (mClipPath != null) {
+ canvas.clipPath(mClipPath);
+ }
mAppWidgetHostView.draw(canvas);
canvas.restoreToCount(saveCount);
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 7a6b4f9..419c3f1 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -110,6 +110,8 @@
mDragController = dragController;
recreateControllers();
+ mOverviewScrim.setup();
+
mWorkspaceDragScrim = new WorkspaceDragScrim((this));
mWorkspaceDragScrim.setWorkspace(workspace);
@@ -118,8 +120,6 @@
mRootView = (LauncherRootView) getParent();
mSysUiScrim = new SysUiScrim(mRootView);
mRootView.setSysUiScrim(mSysUiScrim);
-
-
}
@Override
@@ -555,7 +555,6 @@
public void setInsets(Rect insets) {
super.setInsets(insets);
mSysUiScrim.onInsetsChanged(insets, mAllowSysuiScrims);
- mOverviewScrim.onInsetsChanged(insets);
}
public WorkspaceDragScrim getWorkspaceDragScrim() {
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
index c0c3e5e..53303db 100644
--- a/src/com/android/launcher3/graphics/OverviewScrim.java
+++ b/src/com/android/launcher3/graphics/OverviewScrim.java
@@ -18,10 +18,6 @@
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.graphics.Rect;
import android.util.FloatProperty;
import android.view.View;
import android.view.ViewGroup;
@@ -55,15 +51,15 @@
public OverviewScrim(View view) {
super(view);
- mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
onExtractedColorsChanged(mWallpaperColorInfo);
}
- public void onInsetsChanged(Rect insets) {
- mStableScrimmedView = (OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0
- ? mLauncher.getHotseat()
- : mLauncher.getOverviewPanel();
+ /**
+ * Initializes once view hierarchy is established.
+ */
+ public void setup() {
+ mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
}
public void updateCurrentScrimmedView(ViewGroup root) {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index fd1d965..eb2c551 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -53,10 +53,4 @@
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(0.92f, 0, 0);
}
-
- @Override
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- // Treat the QSB as part of the hotseat so they move together.
- return getHotseatScaleAndTranslation(launcher);
- }
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index fce8fff..d593013 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -59,10 +59,11 @@
float scale = grid.workspaceSpringLoadShrinkFactor;
Rect insets = launcher.getDragLayer().getInsets();
+ int insetsBottom = grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom;
float scaledHeight = scale * ws.getNormalChildHeight();
float shrunkTop = insets.top + grid.dropTargetBarSizePx;
- float shrunkBottom = ws.getMeasuredHeight() - insets.bottom
+ float shrunkBottom = ws.getMeasuredHeight() - insetsBottom
- grid.workspacePadding.bottom
- grid.workspaceSpringLoadedBottomSpace;
float totalShrunkSpace = shrunkBottom - shrunkTop;
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 505c6ce..71aa4ac 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Rect;
+import android.view.LayoutInflater;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.DeviceProfile;
@@ -67,13 +68,28 @@
}
/**
+ * Returns a LayoutInflater that is cloned in this Context, so that Views inflated by it will
+ * have the same Context. (i.e. {@link #lookupContext(Context)} will find this ActivityContext.)
+ */
+ default LayoutInflater getLayoutInflater() {
+ if (this instanceof Context) {
+ Context context = (Context) this;
+ return LayoutInflater.from(context).cloneInContext(context);
+ }
+ return null;
+ }
+
+ /**
* The root view to support drag-and-drop and popup support.
*/
BaseDragLayer getDragLayer();
DeviceProfile getDeviceProfile();
- static <T extends ActivityContext> T lookupContext(Context context) {
+ /**
+ * Returns the ActivityContext associated with the given Context.
+ */
+ static <T extends Context & ActivityContext> T lookupContext(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
} else if (context instanceof ContextWrapper) {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 5c18faf..2e542ed 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
@@ -32,12 +33,14 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AdapterView;
import android.widget.Advanceable;
import android.widget.RemoteViews;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Launcher;
@@ -95,6 +98,18 @@
private final Rect mWidgetSizeAtDrag = new Rect();
private final RectF mTempRectF = new RectF();
private final boolean mIsRtl;
+ private final Rect mEnforcedRectangle = new Rect();
+ private final float mEnforcedCornerRadius;
+ private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
+ outline.setEmpty();
+ } else {
+ outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
+ }
+ }
+ };
public LauncherAppWidgetHostView(Context context) {
super(context);
@@ -112,6 +127,8 @@
mIsRtl = Utilities.isRtl(context.getResources());
mColorExtractor = LocalColorExtractor.newInstance(getContext());
mColorExtractor.setListener(this);
+
+ mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
}
@Override
@@ -169,7 +186,7 @@
if (viewGroup instanceof AdapterView) {
return true;
} else {
- for (int i=0; i < viewGroup.getChildCount(); i++) {
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup) {
if (checkScrollableRecursively((ViewGroup) child)) {
@@ -272,6 +289,8 @@
int pageId = mWorkspace.getPageIndexForScreenId(info.screenId);
updateColorExtraction(mCurrentWidgetSize, pageId);
}
+
+ enforceRoundedCorners();
}
/** Starts the drag mode. */
@@ -469,4 +488,39 @@
}
return false;
}
+
+ @UiThread
+ private void resetRoundedCorners() {
+ setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+ setClipToOutline(false);
+ }
+
+ @UiThread
+ private void enforceRoundedCorners() {
+ if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled(this)) {
+ resetRoundedCorners();
+ return;
+ }
+ View background = RoundedCornerEnforcement.findBackground(this);
+ if (RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
+ resetRoundedCorners();
+ return;
+ }
+ RoundedCornerEnforcement.computeRoundedRectangle(this,
+ background,
+ mEnforcedRectangle);
+ setOutlineProvider(mCornerRadiusEnforcementOutline);
+ setClipToOutline(true);
+ }
+
+ /** Returns the corner radius currently enforced, in pixels. */
+ public float getEnforcedCornerRadius() {
+ return mEnforcedCornerRadius;
+ }
+
+ /** Returns true if the corner radius are enforced for this App Widget. */
+ public boolean hasEnforcedCornerRadius() {
+ return getClipToOutline();
+ }
+
}
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
new file mode 100644
index 0000000..99eccd1
--- /dev/null
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utilities to compute the enforced the use of rounded corners on App Widgets.
+ */
+public class RoundedCornerEnforcement {
+ // This class is only a namespace and not meant to be instantiated.
+ private RoundedCornerEnforcement() {
+ }
+
+ /**
+ * Find the background view for a widget.
+ *
+ * @param appWidget the view containing the App Widget (typically the instance of
+ * {@link AppWidgetHostView}).
+ */
+ @Nullable
+ public static View findBackground(@NonNull View appWidget) {
+ List<View> backgrounds = findViewsWithId(appWidget, android.R.id.background);
+ if (backgrounds.size() == 1) {
+ return backgrounds.get(0);
+ }
+ // Really, the argument should contain the widget, so it cannot be the background.
+ if (appWidget instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) appWidget;
+ if (vg.getChildCount() > 0) {
+ return findUndefinedBackground(vg.getChildAt(0));
+ }
+ }
+ return appWidget;
+ }
+
+ /**
+ * Check whether the app widget has opted out of the enforcement.
+ */
+ public static boolean hasAppWidgetOptedOut(@NonNull View appWidget, @NonNull View background) {
+ return background.getId() == android.R.id.background && background.getClipToOutline();
+ }
+
+ /** 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;
+ }
+
+ /**
+ * Computes the rounded rectangle needed for this app widget.
+ *
+ * @param appWidget View onto which the rounded rectangle will be applied.
+ * @param background Background view. This must be either {@code appWidget} or a descendant
+ * of {@code appWidget}.
+ * @param outRect Rectangle set to the rounded rectangle coordinates, in the reference frame
+ * of {@code appWidget}.
+ */
+ public static void computeRoundedRectangle(@NonNull View appWidget, @NonNull View background,
+ @NonNull Rect outRect) {
+ outRect.left = 0;
+ outRect.right = background.getWidth();
+ outRect.top = 0;
+ outRect.bottom = background.getHeight();
+ while (background != appWidget) {
+ outRect.offset(background.getLeft(), background.getTop());
+ background = (View) background.getParent();
+ }
+ }
+
+ /**
+ * Computes the radius of the rounded rectangle that should be applied to a widget expanded
+ * in the given context.
+ */
+ public static float computeEnforcedRadius(@NonNull Context context) {
+ if (!Utilities.ATLEAST_S) {
+ return 0;
+ }
+ Resources res = context.getResources();
+ float systemRadius = res.getDimension(android.R.dimen.system_app_widget_background_radius);
+ float defaultRadius = res.getDimension(R.dimen.enforced_rounded_corner_max_radius);
+ return Math.min(defaultRadius, systemRadius);
+ }
+
+ private static List<View> findViewsWithId(View view, @IdRes int viewId) {
+ List<View> output = new ArrayList<>();
+ accumulateViewsWithId(view, viewId, output);
+ return output;
+ }
+
+ // Traverse views. If the predicate returns true, continue on the children, otherwise, don't.
+ private static void accumulateViewsWithId(View view, @IdRes int viewId, List<View> output) {
+ if (view.getId() == viewId) {
+ output.add(view);
+ return;
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) view;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ accumulateViewsWithId(vg.getChildAt(i), viewId, output);
+ }
+ }
+ }
+
+ private static boolean isViewVisible(View view) {
+ if (view.getVisibility() != View.VISIBLE) {
+ return false;
+ }
+ return !view.willNotDraw() || view.getForeground() != null || view.getBackground() != null;
+ }
+
+ @Nullable
+ private static View findUndefinedBackground(View current) {
+ if (current.getVisibility() != View.VISIBLE) {
+ return null;
+ }
+ if (isViewVisible(current)) {
+ return current;
+ }
+ View lastVisibleView = null;
+ // Find the first view that is either not a ViewGroup, or a ViewGroup which will draw
+ // something, or a ViewGroup that contains more than one view.
+ if (current instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) current;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ View visibleView = findUndefinedBackground(vg.getChildAt(i));
+ if (visibleView != null) {
+ if (lastVisibleView != null) {
+ return current; // At least two visible children
+ }
+ lastVisibleView = visibleView;
+ }
+ }
+ }
+ return lastVisibleView;
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 267f9f7..2fda86c 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -119,8 +119,7 @@
public void populateAndShow(ItemInfo itemInfo) {
mOriginalItemInfo = itemInfo;
- ((TextView) findViewById(R.id.title)).setText(getContext().getString(
- R.string.widgets_bottom_sheet_title, mOriginalItemInfo.title));
+ ((TextView) findViewById(R.id.title)).setText(mOriginalItemInfo.title);
onWidgetsBound();
attachToContainer();