Merge "Add unit test for CellLayout making sure the reorder are valid and fix Multipage CellLyout" into main
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
index fa9fd2b..b7acb70 100644
--- a/quickstep/res/layout/icon_app_chip_view.xml
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -60,9 +60,8 @@
android:maxLines="1"
android:ellipsize="end"
android:textAlignment="viewStart"
- android:textColor="?androidprv:attr/materialColorOnSurface"
- android:textSize="@dimen/task_thumbnail_icon_menu_text_size"
- android:importantForAccessibility="no" />
+ android:importantForAccessibility="no"
+ style="@style/IconAppChipMenuTextStyle" />
<TextView
android:id="@+id/icon_text_expanded"
@@ -72,9 +71,8 @@
android:maxLines="1"
android:ellipsize="end"
android:textAlignment="viewStart"
- android:textColor="?androidprv:attr/materialColorOnSurface"
- android:textSize="@dimen/task_thumbnail_icon_menu_text_size"
- android:importantForAccessibility="no" />
+ android:importantForAccessibility="no"
+ style="@style/IconAppChipMenuTextStyle" />
<ImageView
android:id="@+id/icon_arrow"
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 295074a..079f01b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -55,7 +55,7 @@
<!-- The max width of the icon menu text -->
<dimen name="task_thumbnail_icon_menu_text_max_width">118dp</dimen>
<!-- The size of the icon menu text -->
- <dimen name="task_thumbnail_icon_menu_text_size">16sp</dimen>
+ <dimen name="task_thumbnail_icon_menu_text_size">14sp</dimen>
<!-- The max width of the thumbnail icon menu background -->
<dimen name="task_thumbnail_icon_menu_background_max_width">164dp</dimen>
<!-- The height of the thumbnail icon menu -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index fc03704..ae62c26 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -303,4 +303,12 @@
<item name="arrowTipBackground">?androidprv:attr/materialColorSurfaceContainer</item>
<item name="arrowTipTextColor">?androidprv:attr/materialColorOnSurface</item>
</style>
+
+ <style name="IconAppChipMenuTextStyle">
+ <item name="android:fontFamily">google-sans-text-medium</item>
+ <item name="android:textSize">@dimen/task_thumbnail_icon_menu_text_size</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ <item name="android:letterSpacing">0.025</item>
+ <item name="android:lineHeight">20sp</item>
+ </style>
</resources>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 165ed80..5b0c8c3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -480,7 +480,11 @@
@Override
public void onDestroy() {
- mAppTransitionManager.onActivityDestroyed();
+ if (mAppTransitionManager != null) {
+ mAppTransitionManager.onActivityDestroyed();
+ }
+ mAppTransitionManager = null;
+
if (mUnfoldTransitionProgressProvider != null) {
SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
mUnfoldTransitionProgressProvider.destroy();
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 95ce406..35fa539 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -238,6 +238,12 @@
if (toState == MODAL_TASK) {
setOverviewSelectEnabled(true);
}
+
+ // Set border after select mode changes to avoid showing border during state transition
+ if (!toState.overviewUi() || toState == MODAL_TASK) {
+ setTaskBorderEnabled(false);
+ }
+
setFreezeViewVisibility(true);
}
@@ -253,6 +259,11 @@
if (finalState != MODAL_TASK) {
setOverviewSelectEnabled(false);
}
+
+ if (finalState.overviewUi() && finalState != MODAL_TASK) {
+ setTaskBorderEnabled(true);
+ }
+
if (finalState != OVERVIEW_SPLIT_SELECT) {
if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.resetState();
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index b542909..5b5d0de 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -145,6 +145,12 @@
if (toState == OVERVIEW_MODAL_TASK) {
setOverviewSelectEnabled(true);
}
+
+ // Set border after select mode changes to avoid showing border during state transition
+ if (!toState.overviewUi || toState == OVERVIEW_MODAL_TASK) {
+ setTaskBorderEnabled(false);
+ }
+
setFreezeViewVisibility(true);
if (mActivity.getDesktopVisibilityController() != null) {
mActivity.getDesktopVisibilityController().onLauncherStateChanged(toState);
@@ -165,6 +171,10 @@
setOverviewSelectEnabled(false);
}
+ if (finalState.overviewUi && finalState != OVERVIEW_MODAL_TASK) {
+ setTaskBorderEnabled(true);
+ }
+
if (isOverlayEnabled) {
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f55dce9..22a5064 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1410,6 +1410,17 @@
}
/**
+ * Enable or disable showing border on hover and focus change on task views
+ */
+ public void setTaskBorderEnabled(boolean enabled) {
+ int taskCount = getTaskViewCount();
+ for (int i = 0; i < taskCount; i++) {
+ TaskView taskView = requireTaskViewAt(i);
+ taskView.setBorderEnabled(enabled);
+ }
+ }
+
+ /**
* Whether the Clear All button is hidden or fully visible. Used to determine if center
* displayed page is a task or the Clear All button.
*
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 49eda8f..af4f402 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -408,6 +408,7 @@
new TaskIdAttributeContainer[2];
private boolean mShowScreenshot;
+ private boolean mBorderEnabled;
// The current background requests to load the task thumbnail and icon
@Nullable
@@ -439,8 +440,15 @@
this(context, attrs, defStyleAttr, 0);
}
- public TaskView(
- Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ this(context, attrs, defStyleAttr, defStyleRes, null, null);
+ }
+
+ @VisibleForTesting
+ public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes, BorderAnimator focusBorderAnimator,
+ BorderAnimator hoverBorderAnimator) {
super(context, attrs, defStyleAttr, defStyleRes);
mActivity = StatefulActivity.fromContext(context);
setOnClickListener(this::onClick);
@@ -457,28 +465,35 @@
TypedArray styledAttrs = context.obtainStyledAttributes(
attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);
- mFocusBorderAnimator = keyboardFocusHighlightEnabled
- ? BorderAnimator.createSimpleBorderAnimator(
- /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
- /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_border_width),
- /* boundsBuilder= */ this::updateBorderBounds,
- /* targetView= */ this,
- /* borderColor= */ styledAttrs.getColor(
- R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR))
- : null;
+ if (focusBorderAnimator != null) {
+ mFocusBorderAnimator = focusBorderAnimator;
+ } else {
+ mFocusBorderAnimator = keyboardFocusHighlightEnabled
+ ? BorderAnimator.createSimpleBorderAnimator(
+ /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
+ /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* boundsBuilder= */ this::updateBorderBounds,
+ /* targetView= */ this,
+ /* borderColor= */ styledAttrs.getColor(
+ R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR))
+ : null;
+ }
- mHoverBorderAnimator = cursorHoverStatesEnabled
- ? BorderAnimator.createSimpleBorderAnimator(
- /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
- /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
- R.dimen.task_hover_border_width),
- /* boundsBuilder= */ this::updateBorderBounds,
- /* targetView= */ this,
- /* borderColor= */ styledAttrs.getColor(
- R.styleable.TaskView_hoverBorderColor, DEFAULT_BORDER_COLOR))
- : null;
-
+ if (hoverBorderAnimator != null) {
+ mHoverBorderAnimator = hoverBorderAnimator;
+ } else {
+ mHoverBorderAnimator = cursorHoverStatesEnabled
+ ? BorderAnimator.createSimpleBorderAnimator(
+ /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
+ /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+ R.dimen.task_hover_border_width),
+ /* boundsBuilder= */ this::updateBorderBounds,
+ /* targetView= */ this,
+ /* borderColor= */ styledAttrs.getColor(
+ R.styleable.TaskView_hoverBorderColor, DEFAULT_BORDER_COLOR))
+ : null;
+ }
styledAttrs.recycle();
}
@@ -538,24 +553,25 @@
}
@Override
- protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ public void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- if (mFocusBorderAnimator != null) {
+ if (mFocusBorderAnimator != null && mBorderEnabled) {
mFocusBorderAnimator.setBorderVisibility(gainFocus, /* animated= */ true);
}
}
@Override
public boolean onHoverEvent(MotionEvent event) {
- if (mHoverBorderAnimator != null) {
+ if (mHoverBorderAnimator != null && mBorderEnabled) {
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
- mHoverBorderAnimator.setBorderVisibility(
- /* visible= */ true, /* animated= */ true);
+ mHoverBorderAnimator.setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
break;
case MotionEvent.ACTION_HOVER_EXIT:
- mHoverBorderAnimator.setBorderVisibility(
- /* visible= */ false, /* animated= */ true);
+ mHoverBorderAnimator.setBorderVisibility(/* visible= */ false, /* animated= */
+ true);
break;
default:
break;
@@ -564,6 +580,24 @@
return super.onHoverEvent(event);
}
+ /**
+ * Enable or disable showing border on hover and focus change
+ */
+ public void setBorderEnabled(boolean enabled) {
+ mBorderEnabled = enabled;
+ // Set the animation correctly in case it misses the hover/focus event during state
+ // transition
+ if (mHoverBorderAnimator != null) {
+ mHoverBorderAnimator.setBorderVisibility(/* visible= */
+ enabled && isHovered(), /* animated= */ true);
+ }
+
+ if (mFocusBorderAnimator != null) {
+ mFocusBorderAnimator.setBorderVisibility(/* visible= */
+ enabled && isFocused(), /* animated= */true);
+ }
+ }
+
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
if (enableCursorHoverStates()) {
@@ -1327,6 +1361,7 @@
mSnapshotView.setThumbnail(mTask, null);
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
+ mBorderEnabled = false;
}
public float getTaskCornerRadius() {
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
new file mode 100644
index 0000000..d744194
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.quickstep.util.BorderAnimator;
+import com.android.quickstep.views.TaskView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class TaskViewTest {
+
+ @Mock
+ private StatefulActivity mContext;
+ @Mock
+ private Resources mResource;
+ @Mock
+ private BorderAnimator mHoverAnimator;
+ @Mock
+ private BorderAnimator mFocusAnimator;
+ private TaskView mTaskView;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mResource.getDisplayMetrics()).thenReturn(mock(DisplayMetrics.class));
+ when(mResource.getConfiguration()).thenReturn(new Configuration());
+
+ when(mContext.getResources()).thenReturn(mResource);
+ when(mContext.getTheme()).thenReturn(mock(Resources.Theme.class));
+ when(mContext.getApplicationInfo()).thenReturn(mock(ApplicationInfo.class));
+ when(mContext.obtainStyledAttributes(any(), any(), anyInt(), anyInt())).thenReturn(
+ mock(TypedArray.class));
+
+ mTaskView = new TaskView(mContext, null, 0, 0, mFocusAnimator, mHoverAnimator);
+ }
+
+ @Test
+ public void notShowBorderOnBorderDisabled() {
+ mTaskView.setBorderEnabled(/* enabled= */ false);
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+ mTaskView.onHoverEvent(MotionEvent.obtain(event));
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+
+ mTaskView.onFocusChanged(false, 0, new Rect());
+ verify(mFocusAnimator, never()).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+ }
+
+ @Test
+ public void showBorderOnBorderEnabled() {
+ mTaskView.setBorderEnabled(/* enabled= */ true);
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+ mTaskView.onHoverEvent(MotionEvent.obtain(event));
+ verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+ mTaskView.onFocusChanged(true, 0, new Rect());
+ verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+ }
+
+ @Test
+ public void hideBorderOnBorderDisabled() {
+ mTaskView.setBorderEnabled(/* enabled= */ false);
+ verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ false, /* animated= */
+ true);
+ verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ false, /* animated= */
+ true);
+ }
+
+ @Test
+ public void notShowBorderByDefault() {
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+ mTaskView.onHoverEvent(MotionEvent.obtain(event));
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
+ true);
+ mTaskView.onFocusChanged(true, 0, new Rect());
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
+ true);
+ }
+}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0099806..9f7575d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -528,6 +528,7 @@
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
+ mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 9a0a6eb..4f2d398 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -34,7 +34,6 @@
import androidx.annotation.NonNull;
import com.android.launcher3.Flags;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -136,14 +135,6 @@
iconCache.updateIconsForPkg(packages[i], mUser);
activitiesLists.put(
packages[i], appsList.updatePackage(context, packages[i], mUser));
-
- // The update may have changed which shortcuts/widgets are available.
- // Refresh the widgets for the package if we have an activity running.
- Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
- if (launcher != null) {
- launcher.refreshAndBindWidgetsForPackageUser(
- new PackageUserKey(packages[i], mUser));
- }
}
}
// Since package was just updated, the target must be available now.
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 96cc412..9e7d4dc 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -24,9 +24,12 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.view.View;
import android.view.View.OnLongClickListener;
+import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.Launcher;
import com.android.launcher3.celllayout.CellInfo;
@@ -40,6 +43,10 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.views.BubbleTextHolder;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
+import com.android.launcher3.widget.PendingItemDragHelper;
+import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetImageView;
/**
* Class to handle long-clicks on workspace items and start drag as a result.
@@ -91,7 +98,46 @@
launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
}
+ private static boolean onWidgetItemLongClick(WidgetCell v) {
+ // Get the widget preview as the drag representation
+ WidgetImageView image = v.getWidgetView();
+ Launcher launcher = Launcher.getLauncher(v.getContext());
+ DragSource dragSource = (target, dragObject, success) -> { };
+
+ // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
+ // we abort the drag.
+ if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
+ return false;
+ }
+
+ PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
+ // RemoteViews are being rendered in AppWidgetHostView in WidgetCell. And thus, the scale of
+ // RemoteViews is equivalent to the AppWidgetHostView scale.
+ dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview(), v.getAppWidgetHostViewScale());
+ dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());
+
+ if (image.getDrawable() != null) {
+ int[] loc = new int[2];
+ launcher.getDragLayer().getLocationInDragLayer(image, loc);
+
+ dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
+ image.getWidth(), new Point(loc[0], loc[1]), dragSource, new DragOptions());
+ } else {
+ NavigableAppWidgetHostView preview = v.getAppWidgetHostViewPreview();
+ int[] loc = new int[2];
+ launcher.getDragLayer().getLocationInDragLayer(preview, loc);
+ Rect r = new Rect();
+ preview.getWorkspaceVisualDragBounds(r);
+ dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
+ new Point(loc[0], loc[1]), dragSource, new DragOptions());
+ }
+ return true;
+ }
+
private static boolean onAllAppsItemLongClick(View view) {
+ if (view instanceof WidgetCell wc) {
+ return onWidgetItemLongClick(wc);
+ }
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onAllAppsItemLongClick");
view.cancelLongPress();
View v = (view instanceof BubbleTextHolder)
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 20bcc3c..bef84f7 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -53,6 +53,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.view.WindowInsetsCompat;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
@@ -315,6 +316,25 @@
}
/**
+ * Returns if the software keyboard is hidden. Hardware keyboards do not display on screen by
+ * default.
+ */
+ default boolean isSoftwareKeyboardHidden() {
+ if (isHardwareKeyboard()) {
+ return true;
+ } else {
+ View dragLayer = getDragLayer();
+ WindowInsets insets = dragLayer.getRootWindowInsets();
+ if (insets == null) {
+ return false;
+ }
+ WindowInsetsCompat insetsCompat =
+ WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer);
+ return !insetsCompat.isVisible(WindowInsetsCompat.Type.ime());
+ }
+ }
+
+ /**
* Sends a pending intent animating from a view.
*
* @param v View to animate.
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
index e70b1cb..40c6115 100644
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -20,15 +20,15 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
/**
* Education view about widgets.
*/
-public class WidgetsEduView extends AbstractSlideInView<Launcher> implements Insettable {
+public class WidgetsEduView extends AbstractSlideInView<BaseActivity> implements Insettable {
private static final int DEFAULT_CLOSE_DURATION = 200;
@@ -124,10 +124,10 @@
}
/** Shows widget education dialog. */
- public static WidgetsEduView showEducationDialog(Launcher launcher) {
- LayoutInflater layoutInflater = LayoutInflater.from(launcher);
+ public static WidgetsEduView showEducationDialog(BaseActivity activity) {
+ LayoutInflater layoutInflater = LayoutInflater.from(activity);
WidgetsEduView v = (WidgetsEduView) layoutInflater.inflate(
- R.layout.widgets_edu, launcher.getDragLayer(), false);
+ R.layout.widgets_edu, activity.getDragLayer(), false);
v.show();
return v;
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index fc9c774..26e191d 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
@@ -35,32 +34,28 @@
import androidx.annotation.Px;
import androidx.core.view.ViewCompat;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.AbstractSlideInView;
-import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ArrowTipView;
/**
* Base class for various widgets popup
*/
-public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
- implements OnClickListener, OnLongClickListener, DragSource,
+public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
+ implements OnClickListener, OnLongClickListener,
PopupDataProvider.PopupDataChangeListener, Insettable, OnDeviceProfileChangeListener {
/** The default number of cells that can fit horizontally in a widget sheet. */
public static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
@@ -129,21 +124,25 @@
} else {
mWidgetInstructionToast = showWidgetToast(getContext(), mWidgetInstructionToast);
}
-
}
@Override
public boolean onLongClick(View v) {
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
v.cancelLongPress();
- if (!ItemLongClickListener.canStartDrag(mActivityContext)) return false;
+ boolean result = false;
if (v instanceof WidgetCell) {
- return beginDraggingWidget((WidgetCell) v);
- } else if (v.getParent() instanceof WidgetCell) {
- return beginDraggingWidget((WidgetCell) v.getParent());
+ result = mActivityContext.getAllAppsItemLongClickListener().onLongClick(v);
+ } else if (v.getParent() instanceof WidgetCell wc) {
+ result = mActivityContext.getAllAppsItemLongClickListener().onLongClick(wc);
+ } else {
+ return true;
}
- return true;
+ if (result) {
+ close(true);
+ }
+ return result;
}
@Override
@@ -212,55 +211,12 @@
MeasureSpec.getSize(heightMeasureSpec));
}
- private boolean beginDraggingWidget(WidgetCell v) {
- // Get the widget preview as the drag representation
- WidgetImageView image = v.getWidgetView();
-
- // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
- // we abort the drag.
- if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
- return false;
- }
-
- PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
- // RemoteViews are being rendered in AppWidgetHostView in WidgetCell. And thus, the scale of
- // RemoteViews is equivalent to the AppWidgetHostView scale.
- dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview(), v.getAppWidgetHostViewScale());
- dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());
-
- if (image.getDrawable() != null) {
- int[] loc = new int[2];
- getPopupContainer().getLocationInDragLayer(image, loc);
-
- dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
- image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
- } else {
- NavigableAppWidgetHostView preview = v.getAppWidgetHostViewPreview();
- int[] loc = new int[2];
- getPopupContainer().getLocationInDragLayer(preview, loc);
- Rect r = new Rect();
- preview.getWorkspaceVisualDragBounds(r);
- dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
- new Point(loc[0], loc[1]), this, new DragOptions());
- }
- close(true);
- return true;
- }
-
@Override
protected Interpolator getIdleInterpolator() {
return mActivityContext.getDeviceProfile().isTablet
? EMPHASIZED : super.getIdleInterpolator();
}
- //
- // Drag related handling methods that implement {@link DragSource} interface.
- //
-
- @Override
- public void onDropCompleted(View target, DragObject d, boolean success) { }
-
-
protected void onCloseComplete() {
super.onCloseComplete();
clearNavBarColor();
@@ -344,7 +300,8 @@
@Override
protected void setTranslationShift(float translationShift) {
super.setTranslationShift(translationShift);
- Launcher launcher = ActivityContext.lookupContext(getContext());
- launcher.onWidgetsTransition(1 - translationShift);
+ if (mActivityContext instanceof Launcher ls) {
+ ls.onWidgetsTransition(1 - translationShift);
+ }
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index af77d03..953ecda 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -55,8 +55,9 @@
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -72,7 +73,6 @@
import com.android.launcher3.views.StickyHeaderLayout;
import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
-import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
@@ -89,7 +89,7 @@
* Popup for showing the full list of available widgets
*/
public class WidgetsFullSheet extends BaseWidgetSheet
- implements ProviderChangedListener, OnActivePageChangedListener,
+ implements OnActivePageChangedListener,
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
private static final long FADE_IN_DURATION = 150;
@@ -166,7 +166,7 @@
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
@Px private int mMaxSpanPerRow;
- private DeviceProfile mDeviceProfile;
+ private final DeviceProfile mDeviceProfile;
private int mOrientation;
@@ -181,7 +181,7 @@
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
+ mDeviceProfile = mActivityContext.getDeviceProfile();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
mOrientation = context.getResources().getConfiguration().orientation;
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
@@ -353,15 +353,14 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
- notifyWidgetProvidersChanged();
+ LauncherAppState.getInstance(mActivityContext).getModel()
+ .refreshAndBindWidgetsAndShortcuts(null);
onRecommendedWidgetsBound();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mActivityContext.getAppWidgetHolder().removeProviderChangeListener(this);
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView
.removeOnAttachStateChangeListener(mBindScrollbarInSearchMode);
if (mHasWorkProfile) {
@@ -482,11 +481,6 @@
}
@Override
- public void notifyWidgetProvidersChanged() {
- mActivityContext.refreshAndBindWidgetsForPackageUser(null);
- }
-
- @Override
public void onWidgetsBound() {
if (mIsInSearchMode) {
return;
@@ -682,22 +676,22 @@
}
/** Shows the {@link WidgetsFullSheet} on the launcher. */
- public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
- boolean isTwoPane = launcher.getDeviceProfile().isTablet
- && launcher.getDeviceProfile().isLandscape
- && (!launcher.getDeviceProfile().isTwoPanels
+ public static WidgetsFullSheet show(BaseActivity activity, boolean animate) {
+ boolean isTwoPane = activity.getDeviceProfile().isTablet
+ && activity.getDeviceProfile().isLandscape
+ && (!activity.getDeviceProfile().isTwoPanels
|| FeatureFlags.UNFOLDED_WIDGET_PICKER.get());
WidgetsFullSheet sheet;
if (isTwoPane) {
- sheet = (WidgetsTwoPaneSheet) launcher.getLayoutInflater().inflate(
+ sheet = (WidgetsTwoPaneSheet) activity.getLayoutInflater().inflate(
R.layout.widgets_two_pane_sheet,
- launcher.getDragLayer(),
+ activity.getDragLayer(),
false);
} else {
- sheet = (WidgetsFullSheet) launcher.getLayoutInflater().inflate(
+ sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
R.layout.widgets_full_sheet,
- launcher.getDragLayer(),
+ activity.getDragLayer(),
false);
}
@@ -754,7 +748,7 @@
/** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
@VisibleForTesting
- public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ public static WidgetsRecyclerView getWidgetsView(BaseActivity launcher) {
return launcher.findViewById(R.id.primary_widgets_list_view);
}
@@ -803,7 +797,7 @@
mOrientation = newConfig.orientation;
if (mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
handleClose(false);
- show(Launcher.getLauncher(getContext()), false);
+ show(BaseActivity.fromContext(getContext()), false);
} else {
reset();
}
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
index d71bf84..41e3ea1 100644
--- a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
@@ -23,8 +23,6 @@
import static org.junit.Assert.assertTrue;
import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowInsets;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -33,6 +31,7 @@
import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.views.ActivityContext;
import org.junit.Before;
import org.junit.Test;
@@ -102,11 +101,8 @@
executeOnLauncher(launcher -> launcher.getAppsView().getSearchUiManager().getEditText()
.hideKeyboard(/* clearFocus= */ false));
- waitForLauncherCondition("Keyboard still visible.", launcher -> {
- View root = launcher.getDragLayer();
- WindowInsets insets = root.getRootWindowInsets();
- return insets != null && !insets.isVisible(WindowInsets.Type.ime());
- });
+ waitForLauncherCondition("Keyboard still visible.",
+ ActivityContext::isSoftwareKeyboardHidden);
mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
mLauncher.unpressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);