diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 842abc399f..7ab09c5ce9 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -103,16 +103,40 @@ android:clearTaskOnLaunch="true" android:exported="false"/> + + android:autoRemoveFromRecents="true" + android:excludeFromRecents="true" + android:screenOrientation="portrait" + android:permission="android.permission.REBOOT" + android:exported="true"> + + + + + + + + + + + + diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml new file mode 100644 index 0000000000..a6a17e5ebc --- /dev/null +++ b/quickstep/res/layout/activity_allset.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index d7bcd9e932..f303f31199 100644 --- a/quickstep/res/layout/overview_panel.xml +++ b/quickstep/res/layout/overview_panel.xml @@ -15,12 +15,6 @@ --> - + + diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml new file mode 100644 index 0000000000..336fb572d5 --- /dev/null +++ b/quickstep/res/values/attrs.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 9c0a083084..4f9b3ebe59 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -99,6 +99,13 @@ 24dp 18dp + + 40dp + 28dp + 80dp + 52dp + 24dp + 8dp 64dp diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index a0f1638c8a..7ada496c40 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -177,6 +177,15 @@ Tutorial %1$d/%2$d + + All set! + + Swipe up to go home + + You\u2019re ready to start using your phone + + Navigation settings for accessibility + Share diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml index 7c7d20a20a..0a8ecb8bde 100644 --- a/quickstep/res/values/styles.xml +++ b/quickstep/res/values/styles.xml @@ -59,7 +59,7 @@ parent="TextAppearance.GestureTutorial"> start ?android:attr/textColorPrimary - google-sans + google-sans-text 0.03 18sp 24sp @@ -99,6 +99,11 @@ @color/gesture_tutorial_primary_color + + Wallpapers - Styles & wallpapers + Wallpaper & style Home settings diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 20b4631dec..c1f3ac5e0d 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -57,6 +57,22 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private final View[] mDragHandles = new View[HANDLE_COUNT]; private final List mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT); + private final OnAttachStateChangeListener mWidgetViewAttachStateChangeListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View view) { + // Do nothing + } + + @Override + public void onViewDetachedFromWindow(View view) { + // When the app widget view is detached, we should close the resize frame. + // An example is when the dragging starts, the widget view is detached from + // CellLayout and then reattached to DragLayout. + close(false); + } + }; + private LauncherAppWidgetHostView mWidgetView; private CellLayout mCellLayout; @@ -177,7 +193,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) { mCellLayout = cellLayout; + if (mWidgetView != null) { + mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); + } mWidgetView = widgetView; + mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) widgetView.getAppWidgetInfo(); mResizeMode = info.resizeMode; @@ -628,6 +648,9 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O @Override protected void handleClose(boolean animate) { mDragLayer.removeView(this); + if (mWidgetView != null) { + mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); + } } @Override diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2f755e11e0..1df9df6763 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -18,6 +18,7 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; +import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; import android.animation.Animator; @@ -193,6 +194,8 @@ public class CellLayout extends ViewGroup { private static final int INVALID_DIRECTION = -100; private final Rect mTempRect = new Rect(); + private final RectF mTempRectF = new RectF(); + private final float[] mTmpFloatArray = new float[4]; private static final Paint sPaint = new Paint(); @@ -1070,11 +1073,16 @@ public class CellLayout extends ViewGroup { // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable. View view = dragObject.dragView.getContentView(); if (view instanceof LauncherAppWidgetHostView) { - Workspace workspace = - Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace(); + Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext()); + Workspace workspace = launcher.getWorkspace(); int screenId = workspace.getIdForScreen(this); int pageId = workspace.getPageIndexForScreenId(screenId); cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect); + + // Now get the rect in drag layer coordinates. + getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false, + mTmpFloatArray, mTempRectF); + Utilities.setRect(mTempRectF, mTempRect); ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId); } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index be5463ec2c..972a6e84f5 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -33,6 +33,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -84,6 +85,7 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.PendingAddShortcutInfo; import java.lang.reflect.Method; @@ -104,6 +106,8 @@ public final class Utilities { private static final Pattern sTrimPattern = Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$"); + private static final float[] sTmpFloatArray = new float[4]; + private static final int[] sLoc0 = new int[2]; private static final int[] sLoc1 = new int[2]; private static final Matrix sMatrix = new Matrix(); @@ -133,6 +137,15 @@ public final class Utilities { Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") || Build.TYPE.toLowerCase(Locale.ROOT).equals("eng"); + /** + * Returns true if theme is dark. + */ + public static boolean isDarkTheme(Context context) { + Configuration configuration = context.getResources().getConfiguration(); + int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; + return nightMode == Configuration.UI_MODE_NIGHT_YES; + } + public static boolean isDevelopersOptionsEnabled(Context context) { return Settings.Global.getInt(context.getApplicationContext().getContentResolver(), Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; @@ -218,6 +231,33 @@ public final class Utilities { return scale; } + /** + * Returns bounds for a child view of DragLayer, in drag layer coordinates. + * + * see {@link com.android.launcher3.dragndrop.DragLayer}. + * + * @param viewBounds Bounds of the view wanted in drag layer coordinates, relative to the view + * itself. eg. (0, 0, view.getWidth, view.getHeight) + * @param ignoreTransform If true, view transform is ignored + * @param outRect The out rect where we return the bounds of {@param view} in drag layer coords. + */ + public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view, + Rect viewBounds, boolean ignoreTransform, float[] recycle, RectF outRect) { + float[] points = recycle == null ? new float[4] : recycle; + points[0] = viewBounds.left; + points[1] = viewBounds.top; + points[2] = viewBounds.right; + points[3] = viewBounds.bottom; + + Utilities.getDescendantCoordRelativeToAncestor(view, dragLayer, points, + false, ignoreTransform); + outRect.set( + Math.min(points[0], points[2]), + Math.min(points[1], points[3]), + Math.max(points[0], points[2]), + Math.max(points[1], points[3])); + } + /** * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}. */ @@ -273,6 +313,16 @@ public final class Utilities { return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]}; } + /** + * Helper method to set rectOut with rectFSrc. + */ + public static void setRect(RectF rectFSrc, Rect rectOut) { + rectOut.left = (int) rectFSrc.left; + rectOut.top = (int) rectFSrc.top; + rectOut.right = (int) rectFSrc.right; + rectOut.bottom = (int) rectFSrc.bottom; + } + public static void scaleRectFAboutCenter(RectF r, float scale) { if (scale != 1.0f) { float cx = r.centerX(); diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index a5852ba828..dbdfb2b663 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -32,6 +32,7 @@ import com.android.launcher3.R; import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.folder.Folder; import com.android.launcher3.keyboard.KeyboardDragAndDropView; import com.android.launcher3.model.data.AppInfo; @@ -290,7 +291,12 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme return actions; } - CellLayout layout = (CellLayout) host.getParent().getParent(); + CellLayout layout; + if (host.getParent() instanceof DragView) { + layout = (CellLayout) ((DragView) host.getParent()).getContentViewParent().getParent(); + } else { + layout = (CellLayout) host.getParent().getParent(); + } if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) { if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) || layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) { diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 119a91ffba..b11b63ed69 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -75,7 +75,7 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag public class AllAppsContainerView extends SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener { - private static final float FLING_VELOCITY_MULTIPLIER = 1800f; + private static final float FLING_VELOCITY_MULTIPLIER = 1000f; // Starts the springs after at least 25% of the animation has passed. private static final float FLING_ANIMATION_THRESHOLD = 0.25f; @@ -611,7 +611,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo public void onAnimationUpdate(ValueAnimator valueAnimator) { if (shouldSpring && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { - absorbSwipeUpVelocity(-Math.abs( + absorbSwipeUpVelocity(Math.abs( Math.round(velocity * FLING_VELOCITY_MULTIPLIER))); shouldSpring = false; } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index c61c0d6d53..c4c7891d58 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -15,13 +15,15 @@ */ package com.android.launcher3.allapps; +import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; -import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; +import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; +import static com.android.launcher3.anim.Interpolators.ACCEL_2; +import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.util.SystemUiController.UI_STATE_ALLAPPS; @@ -154,9 +156,9 @@ public class AllAppsTransitionController return; } - Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW - ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN) - : FAST_OUT_SLOW_IN; + Interpolator interpolator = toState.equals(ALL_APPS) + ? (config.userControlled ? ACCEL_2 : ACCEL_0_75) : + (config.userControlled ? DEACCEL_2 : DEACCEL); Animator anim = createSpringAnimation(mProgress, targetProgress); anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 13ae866efb..e45b8f7918 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -21,7 +21,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; @@ -34,6 +33,7 @@ import android.util.Property; import android.util.SparseArray; import android.view.ContextThemeWrapper; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.GraphicsUtils; @@ -119,9 +119,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable { info, IconPalette.getPreloadProgressColor(context, info.bitmap.color), getPreloadColors(context), - (context.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK - & Configuration.UI_MODE_NIGHT_YES) != 0) /* isDarkMode */; + Utilities.isDarkTheme(context)); } public PreloadIconDrawable( diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java index b3057d5bd2..0eea92c691 100644 --- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java +++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java @@ -94,6 +94,11 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { "SearchActionItemInfo can only have either an Intent or a PendingIntent"); } mIntent = intent; + // bandage fix for just one week + if (intent != null && "com.android.server.telecom".equals(intent.getPackage())) { + intent.setAction(Intent.ACTION_DIAL); + intent.setPackage(null); + } } public PendingIntent getPendingIntent() { diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index c19dfe9300..c63d69dfd3 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -16,7 +16,6 @@ package com.android.launcher3.popup; -import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; @@ -31,6 +30,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -41,17 +41,21 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.InsettableFrameLayout; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.Workspace; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; @@ -59,9 +63,11 @@ import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; +import com.android.launcher3.widget.LocalColorExtractor; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; /** * A container for shortcuts to deep links and notifications associated with an app. @@ -73,6 +79,9 @@ public abstract class ArrowPopup> // +1 for system shortcut view private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1; + // Index used to get background color when using local wallpaper color extraction, + private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50; + private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800; private final Rect mTempRect = new Rect(); @@ -104,8 +113,14 @@ public abstract class ArrowPopup> private Runnable mOnCloseCallback = () -> { }; + // The rect string of the view that the arrow is attached to, in screen reference frame. + private String mArrowColorRectString; private int mArrowColor; private final int[] mColors; + private final HashMap mViewForRect = new HashMap<>(); + + private final int mColorExtractionIndex; + @Nullable private LocalColorExtractor mColorExtractor; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -113,7 +128,9 @@ public abstract class ArrowPopup> mOutlineRadius = Themes.getDialogCornerRadius(context); mLauncher = BaseDraggingActivity.fromContext(context); mIsRtl = Utilities.isRtl(getResources()); - + mColorExtractionIndex = Utilities.isDarkTheme(context) + ? DARK_COLOR_EXTRACTION_INDEX + : LIGHT_COLOR_EXTRACTION_INDEX; setClipToOutline(true); setOutlineProvider(new ViewOutlineProvider() { @Override @@ -158,6 +175,10 @@ public abstract class ArrowPopup> mColors[i] = (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor); } + + if (Utilities.ATLEAST_S) { + setupColorExtraction(); + } } } @@ -342,6 +363,15 @@ public abstract class ArrowPopup> // so we centered it instead. In that case we don't want to showDefaultOptions the arrow. mArrow.setVisibility(INVISIBLE); } else { + updateArrowColor(); + } + + mArrow.setPivotX(mArrowWidth / 2.0f); + mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); + } + + private void updateArrowColor() { + if (!Gravity.isVertical(mGravity)) { mArrow.setBackground(new RoundedArrowDrawable( mArrowWidth, mArrowHeight, mArrowPointRadius, mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(), @@ -350,9 +380,6 @@ public abstract class ArrowPopup> mArrowColor)); mArrow.setElevation(getElevation()); } - - mArrow.setPivotX(mArrowWidth / 2.0f); - mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); } /** @@ -671,6 +698,12 @@ public abstract class ArrowPopup> getPopupContainer().removeView(this); getPopupContainer().removeView(mArrow); mOnCloseCallback.run(); + mArrowColorRectString = null; + mViewForRect.clear(); + if (mColorExtractor != null) { + mColorExtractor.removeLocations(); + mColorExtractor.setListener(null); + } } /** @@ -680,6 +713,68 @@ public abstract class ArrowPopup> mOnCloseCallback = callback; } + private void setupColorExtraction() { + Workspace workspace = mLauncher.findViewById(R.id.workspace); + if (workspace == null) { + return; + } + + mColorExtractor = LocalColorExtractor.newInstance(mLauncher); + mColorExtractor.setListener((rect, extractedColors) -> { + String rectString = rect.toShortString(); + View v = mViewForRect.get(rectString); + if (v != null) { + int newColor = extractedColors.get(mColorExtractionIndex); + setChildColor(v, newColor); + if (rectString.equals(mArrowColorRectString)) { + mArrowColor = newColor; + updateArrowColor(); + } + } + }); + + getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getViewTreeObserver().removeOnPreDrawListener(this); + + ArrayList locations = new ArrayList<>(); + Rect r = new Rect(); + + int count = getChildCount(); + int numVisibleChild = 0; + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + if (view.getVisibility() == VISIBLE) { + RectF rf = new RectF(); + mColorExtractor.getExtractedRectForView(Launcher.getLauncher(getContext()), + workspace.getCurrentPage(), view, rf); + if (rf.isEmpty()) { + numVisibleChild++; + continue; + } + + locations.add(rf); + String rectString = rf.toShortString(); + mViewForRect.put(rectString, view); + + // Arrow color matches the first child or the last child. + if (!mIsAboveIcon && numVisibleChild == 0) { + mArrowColorRectString = rectString; + } else if (mIsAboveIcon) { + mArrowColorRectString = rectString; + } + + numVisibleChild++; + } + } + + mColorExtractor.addLocation(locations); + return false; + } + }); + } + protected BaseDragLayer getPopupContainer() { return mLauncher.getDragLayer(); } diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 2fd5efc3f6..44e55e102c 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -159,6 +159,19 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_X; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + // Don't use device profile here because we know we're in fake landscape, only split option + // available is top/left + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + // Top (visually left) side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollY(); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 6c2f17ee34..d8e5a485fd 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -42,6 +42,10 @@ import java.util.List; */ public interface PagedOrientationHandler { + int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0; + int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1; + int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2; + PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler(); PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler(); PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler(); @@ -71,6 +75,13 @@ public interface PagedOrientationHandler { int getSecondaryDimension(View view); FloatProperty getPrimaryViewTranslate(); FloatProperty getSecondaryViewTranslate(); + + /** + * @param splitPosition The position where the view to be split will go + * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the + * dismissal should happen + */ + int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp); int getPrimaryScroll(View view); float getPrimaryScale(View view); int getChildStart(View view); diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index f6a6448602..d3d77fd99a 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -155,6 +155,25 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_Y; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + if (dp.isLandscape) { + // Left side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } else { + // Top side + return SPLIT_TRANSLATE_SECONDARY_NEGATIVE; + } + } else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) { + // We don't have a bottom option, so should be right + return SPLIT_TRANSLATE_PRIMARY_POSITIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollX(); @@ -277,7 +296,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } else { // Phone Portrait, LargeScreen Landscape/Portrait viewGroup.setOrientation(LinearLayout.HORIZONTAL); - lp.width = LinearLayout.LayoutParams.WRAP_CONTENT; + lp.width = LinearLayout.LayoutParams.MATCH_PARENT; } lp.height = LinearLayout.LayoutParams.WRAP_CONTENT; diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 99942aa56d..06cac08aec 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -22,7 +22,6 @@ import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME; import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; -import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.ColorMatrix; @@ -54,16 +53,12 @@ public class Themes { } public static int getActivityThemeRes(Context context, int wallpaperColorHints) { - Configuration configuration = context.getResources().getConfiguration(); - int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; - boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES; - boolean supportsDarkText = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0; boolean isMainColorDark = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0; - if (darkTheme) { + if (Utilities.isDarkTheme(context)) { return supportsDarkText ? R.style.AppTheme_Dark_DarkText : isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark; } else { diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java index be14e01f0d..f5e1234a28 100644 --- a/src/com/android/launcher3/util/UiThreadHelper.java +++ b/src/com/android/launcher3/util/UiThreadHelper.java @@ -48,7 +48,13 @@ public class UiThreadHelper { WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets(); boolean isImeShown = rootInsets != null && rootInsets.isVisible( WindowInsets.Type.ime()); - if (!isImeShown) return; + if (isImeShown) { + // this call is already asynchronous + launcher.getAppsView().getWindowInsetsController().hide( + WindowInsets.Type.ime() + ); + } + return; } Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget(); diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index d49320b073..81581fa80a 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -233,15 +233,8 @@ public class FloatingIconView extends FrameLayout implements outViewBounds.set(0, 0, v.getWidth(), v.getHeight()); } - float[] points = new float[] {outViewBounds.left, outViewBounds.top, outViewBounds.right, - outViewBounds.bottom}; - Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points, - false, ignoreTransform); - outRect.set( - Math.min(points[0], points[2]), - Math.min(points[1], points[3]), - Math.max(points[0], points[2]), - Math.max(points[1], points[3])); + Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds, + ignoreTransform, null /** recycle */, outRect); } /** diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 620604a4d1..5deecd4c8a 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -16,6 +16,9 @@ package com.android.launcher3.widget; +import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; +import static com.android.launcher3.Utilities.setRect; + import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; @@ -25,7 +28,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.os.SystemClock; -import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.LayoutInflater; @@ -95,11 +97,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView private RectF mLastLocationRegistered = null; @Nullable private AppWidgetHostViewDragListener mDragListener; - // Used to store the widget size during onLayout. + // Used to store the widget sizes in drag layer coordinates. private final Rect mCurrentWidgetSize = new Rect(); private final Rect mWidgetSizeAtDrag = new Rect(); + + private final float[] mTmpFloatArray = new float[4]; 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() { @@ -129,7 +132,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) { setOnLightBackground(true); } - mIsRtl = Utilities.isRtl(context.getResources()); mColorExtractor = LocalColorExtractor.newInstance(getContext()); mColorExtractor.setListener(this); @@ -319,13 +321,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView mIsScrollable = checkScrollableRecursively(this); if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) { - mCurrentWidgetSize.left = left; - mCurrentWidgetSize.top = top; - mCurrentWidgetSize.right = right; - mCurrentWidgetSize.bottom = bottom; LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); - int pageId = mWorkspace.getPageIndexForScreenId(info.screenId); - updateColorExtraction(mCurrentWidgetSize, pageId); + getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true, + mTmpFloatArray, mTempRectF); + setRect(mTempRectF, mCurrentWidgetSize); + updateColorExtraction(mCurrentWidgetSize, + mWorkspace.getPageIndexForScreenId(info.screenId)); } enforceRoundedCorners(); @@ -338,8 +339,8 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView } /** Handles a drag event occurred on a workspace page, {@code pageId}. */ - public void handleDrag(Rect rect, int pageId) { - mWidgetSizeAtDrag.set(rect); + public void handleDrag(Rect rectInDragLayer, int pageId) { + mWidgetSizeAtDrag.set(rectInDragLayer); updateColorExtraction(mWidgetSizeAtDrag, pageId); } @@ -351,53 +352,14 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView requestLayout(); } - private void updateColorExtraction(Rect widgetLocation, int pageId) { - // If the widget hasn't been measured and laid out, we cannot do this. - if (widgetLocation.isEmpty()) { - return; - } - int screenWidth = mLauncher.getDeviceProfile().widthPx; - int screenHeight = mLauncher.getDeviceProfile().heightPx; - int numScreens = mWorkspace.getNumPagesForWallpaperParallax(); - pageId = mIsRtl ? numScreens - pageId - 1 : pageId; - float relativeScreenWidth = 1f / numScreens; - float absoluteTop = widgetLocation.top; - float absoluteBottom = widgetLocation.bottom; - View v = this; - while (v.getParent() instanceof View) { - v = (View) v.getParent(); - if (v.getId() != R.id.launcher) { - break; - } - absoluteBottom += v.getTop(); - absoluteTop += v.getTop(); - } - float xOffset = 0; - View parentView = (View) getParent(); - // The layout depends on the orientation. - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - int parentViewWidth = parentView == null ? 0 : parentView.getWidth(); - xOffset = screenWidth - mWorkspace.getPaddingRight() - parentViewWidth; - } else { - int parentViewPaddingLeft = parentView == null ? 0 : parentView.getPaddingLeft(); - xOffset = mWorkspace.getPaddingLeft() + parentViewPaddingLeft; - } - // This is the position of the widget relative to the wallpaper, as expected by the - // local color extraction of the WallpaperManager. - // The coordinate system is such that, on the horizontal axis, each screen has a - // distinct range on the [0,1] segment. So if there are 3 screens, they will have the - // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be - // the position of the widget relative to the screen. For the vertical axis, this is - // simply the location of the widget relative to the screen. - mTempRectF.left = ((widgetLocation.left + xOffset) / screenWidth + pageId) - * relativeScreenWidth; - mTempRectF.right = ((widgetLocation.right + xOffset) / screenWidth + pageId) - * relativeScreenWidth; - mTempRectF.top = absoluteTop / screenHeight; - mTempRectF.bottom = absoluteBottom / screenHeight; - if (mTempRectF.left < 0 || mTempRectF.right > 1 || mTempRectF.top < 0 - || mTempRectF.bottom > 1) { - Log.e(LOG_TAG, " Error, invalid relative position"); + /** + * @param rectInDragLayer Rect of widget in drag layer coordinates. + * @param pageId The workspace page the widget is on. + */ + private void updateColorExtraction(Rect rectInDragLayer, int pageId) { + mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF); + + if (mTempRectF.isEmpty()) { return; } if (!mTempRectF.equals(mLastLocationRegistered)) { diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java index be4faea68f..8ae6b2e435 100644 --- a/src/com/android/launcher3/widget/LocalColorExtractor.java +++ b/src/com/android/launcher3/widget/LocalColorExtractor.java @@ -19,11 +19,14 @@ package com.android.launcher3.widget; import android.app.WallpaperColors; import android.appwidget.AppWidgetHostView; import android.content.Context; +import android.graphics.Rect; import android.graphics.RectF; import android.util.SparseIntArray; +import android.view.View; import androidx.annotation.Nullable; +import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.util.ResourceBasedOverride; @@ -71,4 +74,33 @@ public class LocalColorExtractor implements ResourceBasedOverride { * Updates the base context to contain the colors override */ public void applyColorsOverride(Context base, WallpaperColors colors) { } + + /** + * Takes a view and returns its rect that can be used by the wallpaper local color extractor. + * + * @param launcher Launcher class class. + * @param pageId The page the workspace item is on. + * @param v The view. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public void getExtractedRectForView(Launcher launcher, int pageId, View v, + RectF colorExtractionRectOut) { + // no-op + } + + /** + * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper + * local color extractor. + * + * @param launcher Launcher class. + * @param pageId The page the workspace item is on. + * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public void getExtractedRectForViewRect(Launcher launcher, int pageId, Rect rectInDragLayer, + RectF colorExtractionRectOut) { + // no-op + } }