From e9c897080c3db0c18b1e1941ccf08943ab194ee3 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 23 Mar 2018 14:36:03 -0700 Subject: [PATCH 01/81] Making read permission for android content provider as systemSignature to prevent unwanted access to user data Bug: 74360014 Change-Id: I0155c25d91609f4492f56b221c372ec3f51442e3 --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c3ddfd62b8..fde22ebc54 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -34,7 +34,7 @@ Date: Mon, 26 Mar 2018 12:10:31 -0700 Subject: [PATCH 02/81] Adding a custom view for DragHandle > Separating page indicator and drag handle > Page indicator always draws irrespactive of oriantation > Drag handle is responsible for accessibility interactions > Adding assissibility actions for DragHandle Bug: 72500733 Change-Id: I9030337456964af1bdf77f1c01956452321f9229 --- .../res/layout/drag_handle_indicator.xml | 23 +++ quickstep/res/values/strings.xml | 3 + .../launcher3/uioverrides/OverviewState.java | 5 +- .../launcher3/uioverrides/UiFactory.java | 15 -- .../views/QuickstepDragIndicator.java | 78 +++++++++++ res/layout/drag_handle_indicator.xml | 23 +++ res/layout/hotseat.xml | 9 -- res/layout/launcher.xml | 6 +- res/values/dimens.xml | 1 - src/com/android/launcher3/DeviceProfile.java | 28 ++++ src/com/android/launcher3/Hotseat.java | 24 +--- src/com/android/launcher3/Launcher.java | 12 ++ src/com/android/launcher3/LauncherState.java | 7 +- src/com/android/launcher3/Workspace.java | 11 -- .../WorkspaceStateTransitionAnimation.java | 16 ++- .../allapps/AllAppsTransitionController.java | 1 + .../WorkspacePageIndicator.java | 96 +++---------- .../views/LauncherDragIndicator.java | 132 ++++++++++++++++++ .../OverviewAccessibilityDelegate.java | 68 --------- .../launcher3/uioverrides/UiFactory.java | 15 -- 20 files changed, 348 insertions(+), 225 deletions(-) create mode 100644 quickstep/res/layout/drag_handle_indicator.xml create mode 100644 quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java create mode 100644 res/layout/drag_handle_indicator.xml create mode 100644 src/com/android/launcher3/views/LauncherDragIndicator.java delete mode 100644 src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java diff --git a/quickstep/res/layout/drag_handle_indicator.xml b/quickstep/res/layout/drag_handle_indicator.xml new file mode 100644 index 0000000000..9ee05d5ad5 --- /dev/null +++ b/quickstep/res/layout/drag_handle_indicator.xml @@ -0,0 +1,23 @@ + + + diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index ec8eb5274b..c36e1ff18d 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -29,4 +29,7 @@ Swipe up from the bottom to switch apps + + + Overview \ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index abbf45e2a1..52faa517f8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -113,8 +113,9 @@ public class OverviewState extends LauncherState { // TODO: Remove hotseat from overview return HOTSEAT_ICONS; } else { - return launcher.getAppsView().getFloatingHeaderView().hasVisibleContent() - ? HOTSEAT_EXTRA | ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS | HOTSEAT_EXTRA; + return HOTSEAT_SEARCH_BOX | DRAG_HANDLE_INDICATOR | + (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent() + ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 846e80377e..5d975b0f61 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -21,14 +21,10 @@ import static com.android.quickstep.OverviewInteractionState.KEY_SWIPE_UP_ENABLE import android.content.Context; import android.content.SharedPreferences; -import android.view.View; -import android.view.View.AccessibilityDelegate; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherStateManager.StateHandler; -import com.android.launcher3.R; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.RecentsModel; @@ -59,10 +55,6 @@ public class UiFactory { } } - public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() { - return null; - } - public static StateHandler[] getStateHandler(Launcher launcher) { return new StateHandler[] { launcher.getAllAppsController(), launcher.getWorkspace(), @@ -99,11 +91,4 @@ public class UiFactory { model.onTrimMemory(level); } } - - public static View[] getHotseatExtraContent(Hotseat hotseat) { - return new View[] { - hotseat.findViewById(R.id.drag_indicator), - hotseat.findViewById(R.id.search_container_hotseat), - }; - } } diff --git a/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java new file mode 100644 index 0000000000..82ec84ec62 --- /dev/null +++ b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 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.views; + +import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.LauncherState.OVERVIEW; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.android.launcher3.R; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; +import com.android.launcher3.views.LauncherDragIndicator; + +public class QuickstepDragIndicator extends LauncherDragIndicator { + + public QuickstepDragIndicator(Context context) { + super(context); + } + + public QuickstepDragIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public QuickstepDragIndicator(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + private boolean isInOverview() { + return mLauncher.isInState(OVERVIEW); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + if (isInOverview()) { + info.setContentDescription(getContext().getString(R.string.all_apps_button_label)); + } + } + + @Override + protected void initCustomActions(AccessibilityNodeInfo info) { + if (!isInOverview()) { + super.initCustomActions(info); + } + } + + @Override + public void onClick(View view) { + if (isInOverview()) { + mLauncher.getUserEventDispatcher().logActionOnControl( + Action.Touch.TAP, ControlType.ALL_APPS_BUTTON, ContainerType.TASKSWITCHER); + mLauncher.getStateManager().goToState(ALL_APPS); + super.onClick(view); + } else { + mLauncher.getUserEventDispatcher().logActionOnControl( + Action.Touch.TAP, ControlType.ALL_APPS_BUTTON, ContainerType.WORKSPACE); + mLauncher.getStateManager().goToState(OVERVIEW); + } + } +} diff --git a/res/layout/drag_handle_indicator.xml b/res/layout/drag_handle_indicator.xml new file mode 100644 index 0000000000..d5a7b8a038 --- /dev/null +++ b/res/layout/drag_handle_indicator.xml @@ -0,0 +1,23 @@ + + + diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml index 01cd92a63d..00f0b5ff8a 100644 --- a/res/layout/hotseat.xml +++ b/res/layout/hotseat.xml @@ -18,15 +18,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto"> - - + + 2dp 80dp 0dp - 24dp 8dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 13971ad95a..14d8b93da8 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -117,6 +117,7 @@ public class DeviceProfile { // Insets private final Rect mInsets = new Rect(); public final Rect workspacePadding = new Rect(); + private final Rect mHotseatPadding = new Rect(); // Icon badges public BadgeRenderer mBadgeRenderer; @@ -456,6 +457,33 @@ public class DeviceProfile { } } + public Rect getHotseatLayoutPadding() { + if (isVerticalBarLayout()) { + if (isSeascape()) { + mHotseatPadding.set( + mInsets.left, mInsets.top, hotseatBarSidePaddingPx, mInsets.bottom); + } else { + mHotseatPadding.set( + hotseatBarSidePaddingPx, mInsets.top, mInsets.right, mInsets.bottom); + } + } else { + + // We want the edges of the hotseat to line up with the edges of the workspace, but the + // icons in the hotseat are a different size, and so don't line up perfectly. To account + // for this, we pad the left and right of the hotseat with half of the difference of a + // workspace cell vs a hotseat cell. + float workspaceCellWidth = (float) widthPx / inv.numColumns; + float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons; + int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2); + mHotseatPadding.set( + hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx, + hotseatBarTopPaddingPx, + hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx, + hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx); + } + return mHotseatPadding; + } + /** * @return the bounds for which the open folders should be contained within */ diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 211a75656b..96604689fc 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -152,19 +152,13 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett if (mHasVerticalHotseat) { mContent.setGridSize(1, grid.inv.numHotseatIcons); - lp.height = ViewGroup.LayoutParams.MATCH_PARENT; if (grid.isSeascape()) { lp.gravity = Gravity.LEFT; lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx; - getLayout().setPadding( - insets.left, insets.top, grid.hotseatBarSidePaddingPx, insets.bottom); - } else { lp.gravity = Gravity.RIGHT; lp.width = grid.hotseatBarSizePx + insets.right + grid.hotseatBarSidePaddingPx; - getLayout().setPadding( - grid.hotseatBarSidePaddingPx, insets.top, insets.right, insets.bottom); } } else { mContent.setGridSize(grid.inv.numHotseatIcons, 1); @@ -172,22 +166,10 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett lp.gravity = Gravity.BOTTOM; lp.width = ViewGroup.LayoutParams.MATCH_PARENT; lp.height = grid.hotseatBarSizePx + insets.bottom; - - // We want the edges of the hotseat to line up with the edges of the workspace, but the - // icons in the hotseat are a different size, and so don't line up perfectly. To account for - // this, we pad the left and right of the hotseat with half of the difference of a workspace - // cell vs a hotseat cell. - float workspaceCellWidth = (float) grid.widthPx / grid.inv.numColumns; - float hotseatCellWidth = (float) grid.widthPx / grid.inv.numHotseatIcons; - int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2); - Rect workspacePadding = grid.workspacePadding; - - getLayout().setPadding( - hotseatAdjustment + workspacePadding.left + grid.cellLayoutPaddingLeftRightPx, - grid.hotseatBarTopPaddingPx, - hotseatAdjustment + workspacePadding.right + grid.cellLayoutPaddingLeftRightPx, - grid.hotseatBarBottomPaddingPx + insets.bottom + grid.cellLayoutBottomPaddingPx); } + Rect padding = grid.getHotseatLayoutPadding(); + getLayout().setPadding(padding.left, padding.top, padding.right, padding.bottom); + setLayoutParams(lp); InsettableFrameLayout.dispatchInsets(this, insets); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ed94aa4382..13f0aed2f4 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -197,6 +197,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L private final int[] mTmpAddItemCellCoordinates = new int[2]; @Thunk Hotseat mHotseat; + private View mDragHandleIndicator; + @Nullable private View mHotseatSearchBox; private DropTargetBar mDropTargetBar; @@ -938,6 +940,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L mWorkspace.initParentViews(mDragLayer); mOverviewPanel = findViewById(R.id.overview_panel); mHotseat = findViewById(R.id.hotseat); + mDragHandleIndicator = findViewById(R.id.drag_indicator); + mHotseatSearchBox = findViewById(R.id.search_container_hotseat); mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION @@ -1201,6 +1205,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L return mHotseat; } + public View getDragHandleIndicator() { + return mDragHandleIndicator; + } + + public View getHotseatSearchBox() { + return mHotseatSearchBox; + } + public T getOverviewPanel() { return (T) mOverviewPanel; } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index b1bf6ec6ef..21f9d5acaa 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -47,10 +47,11 @@ public class LauncherState { */ public static final int NONE = 0; public static final int HOTSEAT_ICONS = 1 << 0; - public static final int HOTSEAT_EXTRA = 1 << 1; // e.g. a search box + public static final int HOTSEAT_SEARCH_BOX = 1 << 1; public static final int ALL_APPS_HEADER = 1 << 2; public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions public static final int ALL_APPS_CONTENT = 1 << 4; + public static final int DRAG_HANDLE_INDICATOR = 1 << 5; protected static final int FLAG_SHOW_SCRIM = 1 << 0; protected static final int FLAG_MULTI_PAGE = 1 << 1; @@ -201,9 +202,9 @@ public class LauncherState { public int getVisibleElements(Launcher launcher) { if (launcher.getDeviceProfile().isVerticalBarLayout()) { - return HOTSEAT_ICONS; + return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR; } - return HOTSEAT_ICONS | HOTSEAT_EXTRA; + return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR | HOTSEAT_SEARCH_BOX; } /** diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 68ad253700..34ae8ea3d1 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -443,12 +443,6 @@ public class Workspace extends PagedView setWallpaperDimension(); } - @Override - public void initParentViews(View parent) { - super.initParentViews(parent); - mPageIndicator.setAccessibilityDelegate(UiFactory.newPageIndicatorAccessibilityDelegate()); - } - private void setupLayoutTransition() { // We want to show layout transitions when pages are deleted, to close the gap. mLayoutTransition = new LayoutTransition(); @@ -3350,11 +3344,6 @@ public class Workspace extends PagedView ? mLauncher.getDeviceProfile().widthPx : getMeasuredWidth(); } - @Override - protected String getPageIndicatorDescription() { - return getResources().getString(R.string.all_apps_button_label); - } - @Override protected String getCurrentPageDescription() { int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 3a222c261c..fa86906cf6 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -18,8 +18,9 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherState.HOTSEAT_EXTRA; +import static com.android.launcher3.LauncherState.DRAG_HANDLE_INDICATOR; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; +import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import android.view.View; @@ -81,16 +82,19 @@ public class WorkspaceStateTransitionAnimation { int elements = state.getVisibleElements(mLauncher); float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; - float hotseatExtraAlpha = (elements & HOTSEAT_EXTRA) != 0 ? 1 : 0; propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha, pageAlphaProvider.interpolator); - for (View hotseatExtraContent : UiFactory.getHotseatExtraContent(mLauncher.getHotseat())) { - propertySetter.setViewAlpha(hotseatExtraContent, hotseatExtraAlpha, - pageAlphaProvider.interpolator); - } propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), hotseatIconsAlpha, pageAlphaProvider.interpolator); + propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(), + (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0, + pageAlphaProvider.interpolator); + + propertySetter.setViewAlpha(mLauncher.getDragHandleIndicator(), + (elements & DRAG_HANDLE_INDICATOR) != 0 ? 1 : 0, + pageAlphaProvider.interpolator); + // Set scrim propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS, state.hasScrim ? 1 : 0, Interpolators.LINEAR); diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 9be123f973..aafae10976 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -122,6 +122,7 @@ public class AllAppsTransitionController if (!mIsVerticalLayout) { mLauncher.getHotseat().setTranslationY(hotseatTranslation); mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation); + mLauncher.getDragHandleIndicator().setTranslationY(hotseatTranslation); } // Use a light system UI (dark icons) if all apps is behind at least half of the diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java index 94ae39bb5c..4ad7feb903 100644 --- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java +++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java @@ -1,9 +1,5 @@ package com.android.launcher3.pageindicators; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -import static com.android.launcher3.LauncherState.ALL_APPS; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -20,9 +16,7 @@ import android.util.AttributeSet; import android.util.Property; import android.view.Gravity; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewConfiguration; -import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; @@ -31,18 +25,13 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dynamicui.WallpaperColorInfo; -import com.android.launcher3.userevent.nano.LauncherLogProto.Action; -import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; /** - * A PageIndicator that briefly shows a fraction of a line when moving between pages in - * portrait mode. In Landscape simply draws the caret drawable bottom-corner aligned in - * the drag-layer. + * A PageIndicator that briefly shows a fraction of a line when moving between pages * * The fraction is 1 / number of pages and the position is based on the progress of the page scroll. */ -public class WorkspacePageIndicator extends View - implements Insettable, OnClickListener, PageIndicator { +public class WorkspacePageIndicator extends View implements Insettable, PageIndicator { private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration(); private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay(); @@ -57,7 +46,6 @@ public class WorkspacePageIndicator extends View private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper()); private final Launcher mLauncher; - private final AccessibilityManager mAccessibilityManager; private boolean mShouldAutoHide = true; @@ -72,8 +60,6 @@ public class WorkspacePageIndicator extends View private Paint mLinePaint; private final int mLineHeight; - private boolean mIsLandscapeUi; - private static final Property PAINT_ALPHA = new Property(Integer.class, "paint_alpha") { @Override @@ -84,7 +70,7 @@ public class WorkspacePageIndicator extends View @Override public void set(WorkspacePageIndicator obj, Integer alpha) { obj.mLinePaint.setAlpha(alpha); - obj.invalidateIfPortrait(); + obj.invalidate(); } }; @@ -98,7 +84,7 @@ public class WorkspacePageIndicator extends View @Override public void set(WorkspacePageIndicator obj, Float numPages) { obj.mNumPagesFloat = numPages; - obj.invalidateIfPortrait(); + obj.invalidate(); } }; @@ -112,7 +98,7 @@ public class WorkspacePageIndicator extends View @Override public void set(WorkspacePageIndicator obj, Integer totalScroll) { obj.mTotalScroll = totalScroll; - obj.invalidateIfPortrait(); + obj.invalidate(); } }; @@ -139,24 +125,23 @@ public class WorkspacePageIndicator extends View boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText(); mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA; mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE); - mAccessibilityManager = (AccessibilityManager) - getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); } @Override protected void onDraw(Canvas canvas) { - if (mTotalScroll == 0 || mNumPagesFloat == 0 || mIsLandscapeUi) { + if (mTotalScroll == 0 || mNumPagesFloat == 0) { return; } // Compute and draw line rect. float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f); - int availableWidth = canvas.getWidth(); + int availableWidth = getWidth(); int lineWidth = (int) (availableWidth / mNumPagesFloat); int lineLeft = (int) (progress * (availableWidth - lineWidth)); int lineRight = lineLeft + lineWidth; - canvas.drawRoundRect(lineLeft, canvas.getHeight() / 2 - mLineHeight / 2, lineRight, - canvas.getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint); + + canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight, + getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint); } @Override @@ -172,7 +157,7 @@ public class WorkspacePageIndicator extends View } else if (mTotalScroll != totalScroll) { animateToTotalScroll(totalScroll); } else { - invalidateIfPortrait(); + invalidate(); } if (mShouldAutoHide) { @@ -191,7 +176,13 @@ public class WorkspacePageIndicator extends View @Override public void setMarkersCount(int numMarkers) { if (Float.compare(numMarkers, mNumPagesFloat) != 0) { - animateToNumPages(numMarkers); + setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers), + NUM_PAGES_ANIMATOR_INDEX); + } else { + if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) { + mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel(); + mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null; + } } } @@ -219,11 +210,6 @@ public class WorkspacePageIndicator extends View LINE_ALPHA_ANIMATOR_INDEX); } - private void animateToNumPages(int numPages) { - setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages), - NUM_PAGES_ANIMATOR_INDEX); - } - private void animateToTotalScroll(int totalScroll) { setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll), TOTAL_SCROLL_ANIMATOR_INDEX); @@ -254,54 +240,18 @@ public class WorkspacePageIndicator extends View @Override public void setInsets(Rect insets) { DeviceProfile grid = mLauncher.getDeviceProfile(); - mIsLandscapeUi = grid.isVerticalBarLayout(); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - if (mIsLandscapeUi) { - if (grid.isSeascape()) { - lp.leftMargin = grid.hotseatBarSidePaddingPx; - lp.rightMargin = insets.right; - lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; - } else { - lp.leftMargin = insets.left; - lp.rightMargin = grid.hotseatBarSidePaddingPx; - lp.gravity = Gravity.LEFT | Gravity.BOTTOM; - } - lp.bottomMargin = grid.workspacePadding.bottom; - lp.width = lp.height = getResources() - .getDimensionPixelSize(R.dimen.dynamic_grid_min_page_indicator_size); - - setBackgroundResource(R.drawable.all_apps_handle_landscape); - setOnFocusChangeListener(mLauncher.mFocusHandler); - setOnClickListener(this); - + if (grid.isVerticalBarLayout()) { + Rect padding = grid.workspacePadding; + lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx; + lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx; + lp.bottomMargin = padding.bottom; } else { lp.leftMargin = lp.rightMargin = 0; lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; - lp.height = grid.pageIndicatorSizePx; lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom; - lp.width = MATCH_PARENT; - - setBackgroundResource(0); - setOnFocusChangeListener(null); - setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null); } - setLayoutParams(lp); } - - private void invalidateIfPortrait() { - if (!mIsLandscapeUi) { - invalidate(); - } - } - - @Override - public void onClick(View view) { - if (!mLauncher.isInState(ALL_APPS)) { - mLauncher.getUserEventDispatcher().logActionOnControl( - Action.Touch.TAP, ControlType.ALL_APPS_BUTTON); - mLauncher.getStateManager().goToState(ALL_APPS); - } - } } diff --git a/src/com/android/launcher3/views/LauncherDragIndicator.java b/src/com/android/launcher3/views/LauncherDragIndicator.java new file mode 100644 index 0000000000..f15129cf48 --- /dev/null +++ b/src/com/android/launcher3/views/LauncherDragIndicator.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 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.views; + +import static com.android.launcher3.LauncherState.ALL_APPS; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Insettable; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; + +public class LauncherDragIndicator extends ImageView implements Insettable, OnClickListener { + + private static final int WALLPAPERS = R.string.wallpaper_button_text; + private static final int WIDGETS = R.string.widget_button_text; + private static final int SETTINGS = R.string.settings_button_text; + + protected final Launcher mLauncher; + + public LauncherDragIndicator(Context context) { + this(context, null); + } + + public LauncherDragIndicator(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LauncherDragIndicator(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mLauncher = Launcher.getLauncher(context); + setOnClickListener(this); + } + + @Override + public void setInsets(Rect insets) { + DeviceProfile grid = mLauncher.getDeviceProfile(); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); + + if (grid.isVerticalBarLayout()) { + if (grid.isSeascape()) { + lp.leftMargin = grid.hotseatBarSidePaddingPx; + lp.rightMargin = insets.right; + lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; + } else { + lp.leftMargin = insets.left; + lp.rightMargin = grid.hotseatBarSidePaddingPx; + lp.gravity = Gravity.LEFT | Gravity.BOTTOM; + } + lp.bottomMargin = grid.workspacePadding.bottom; + setImageResource(R.drawable.all_apps_handle_landscape); + } else { + lp.leftMargin = lp.rightMargin = 0; + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + lp.bottomMargin = getPortraitBottomMargin(grid, insets); + setImageResource(R.drawable.ic_drag_indicator); + } + + lp.width = lp.height = grid.pageIndicatorSizePx; + setLayoutParams(lp); + } + + protected int getPortraitBottomMargin(DeviceProfile grid, Rect insets) { + return grid.hotseatBarSizePx + insets.bottom - grid.pageIndicatorSizePx; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + initCustomActions(info); + } + + protected void initCustomActions(AccessibilityNodeInfo info) { + Context context = getContext(); + if (Utilities.isWallpaperAllowed(context)) { + info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS))); + } + info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS))); + info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS))); + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + Launcher launcher = Launcher.getLauncher(getContext()); + if (action == WALLPAPERS) { + launcher.onClickWallpaperPicker(this); + return true; + } else if (action == WIDGETS) { + return OptionsPopupView.onWidgetsClicked(launcher); + } else if (action == SETTINGS) { + OptionsPopupView.startSettings(launcher); + return true; + } + return super.performAccessibilityAction(action, arguments); + } + + @Override + public void onClick(View view) { + if (!mLauncher.isInState(ALL_APPS)) { + mLauncher.getUserEventDispatcher().logActionOnControl( + Action.Touch.TAP, ControlType.ALL_APPS_BUTTON); + mLauncher.getStateManager().goToState(ALL_APPS); + } + } +} diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java deleted file mode 100644 index d9ce87c7c5..0000000000 --- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016 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.uioverrides; - -import android.content.Context; -import android.os.Bundle; -import android.view.View; -import android.view.View.AccessibilityDelegate; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; - -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.views.OptionsPopupView; - -/** - * Accessibility delegate with actions pointing to various Overview entry points. - */ -public class OverviewAccessibilityDelegate extends AccessibilityDelegate { - - private static final int WALLPAPERS = R.string.wallpaper_button_text; - private static final int WIDGETS = R.string.widget_button_text; - private static final int SETTINGS = R.string.settings_button_text; - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - - Context context = host.getContext(); - - if (Utilities.isWallpaperAllowed(context)) { - info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS))); - } - info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS))); - info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS))); - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - Launcher launcher = Launcher.getLauncher(host.getContext()); - if (action == WALLPAPERS) { - launcher.onClickWallpaperPicker(host); - return true; - } else if (action == WIDGETS) { - return OptionsPopupView.onWidgetsClicked(launcher); - } else if (action == SETTINGS) { - OptionsPopupView.startSettings(launcher); - return true; - } - return super.performAccessibilityAction(host, action, args); - } -} diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 2f1de7bf64..e0b76fd0d4 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -16,13 +16,8 @@ package com.android.launcher3.uioverrides; -import android.view.View; -import android.view.View.AccessibilityDelegate; - -import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherStateManager.StateHandler; -import com.android.launcher3.R; import com.android.launcher3.util.TouchController; public class UiFactory { @@ -32,10 +27,6 @@ public class UiFactory { launcher.getDragController(), new AllAppsSwipeController(launcher)}; } - public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() { - return new OverviewAccessibilityDelegate(); - } - public static StateHandler[] getStateHandler(Launcher launcher) { return new StateHandler[] { launcher.getAllAppsController(), launcher.getWorkspace() }; @@ -48,10 +39,4 @@ public class UiFactory { public static void onStart(Launcher launcher) { } public static void onTrimMemory(Launcher launcher, int level) { } - - public static View[] getHotseatExtraContent(Hotseat hotseat) { - return new View[] { - hotseat.findViewById(R.id.drag_indicator), - }; - } } From 11e96498947a10abafa7ffe17f85bd4b9162c6d6 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 23 Mar 2018 17:06:00 -0700 Subject: [PATCH 03/81] Do not clear grid accupancy if nothing changes Hotseat is calling setGridSize on every layout which was clearing gridOccupancy, marking the cells as empty Bug: 73867732 Change-Id: Ie07f5786f2e5bfe2340fd0b8723964f651c929d4 --- src/com/android/launcher3/Hotseat.java | 17 +++++++++-------- src/com/android/launcher3/Launcher.java | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 96604689fc..c6025fe5f7 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -81,12 +81,17 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett protected void onFinishInflate() { super.onFinishInflate(); mContent = findViewById(R.id.layout); - - resetLayout(); } - void resetLayout() { + void resetLayout(boolean hasVerticalHotseat) { mContent.removeAllViewsInLayout(); + mHasVerticalHotseat = hasVerticalHotseat; + InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv; + if (hasVerticalHotseat) { + mContent.setGridSize(1, idp.numHotseatIcons); + } else { + mContent.setGridSize(idp.numHotseatIcons, 1); + } if (!FeatureFlags.NO_ALL_APPS_ICON) { // Add the Apps button @@ -148,10 +153,8 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett public void setInsets(Rect insets) { FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); DeviceProfile grid = mLauncher.getDeviceProfile(); - mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout(); - if (mHasVerticalHotseat) { - mContent.setGridSize(1, grid.inv.numHotseatIcons); + if (grid.isVerticalBarLayout()) { lp.height = ViewGroup.LayoutParams.MATCH_PARENT; if (grid.isSeascape()) { lp.gravity = Gravity.LEFT; @@ -161,8 +164,6 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett lp.width = grid.hotseatBarSizePx + insets.right + grid.hotseatBarSidePaddingPx; } } else { - mContent.setGridSize(grid.inv.numHotseatIcons, 1); - lp.gravity = Gravity.BOTTOM; lp.width = ViewGroup.LayoutParams.MATCH_PARENT; lp.height = grid.hotseatBarSizePx + insets.bottom; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 13f0aed2f4..43a781d4e1 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1840,7 +1840,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L mAppWidgetHost.clearViews(); if (mHotseat != null) { - mHotseat.resetLayout(); + mHotseat.resetLayout(mDeviceProfile.isVerticalBarLayout()); } TraceHelper.endSection("startBinding"); } From 00c9c9a6fc551fef89658a11abe544248247f3b6 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 26 Mar 2018 15:33:41 -0700 Subject: [PATCH 04/81] Adding an empty message in RecentsView Moving the content instead of translating the view. This ensures that the empty message fades in place while the other content come-in from the side. Change-Id: I081d2e21206de24ad530814cb6a8ca7c3e293724 --- quickstep/res/drawable/ic_empty_recents.xml | 30 ++++++ quickstep/res/values/dimens.xml | 4 + quickstep/res/values/strings.xml | 3 + .../RecentsViewStateController.java | 2 + .../quickstep/FallbackRecentsView.java | 21 +++++ .../quickstep/views/LauncherRecentsView.java | 32 +++++-- .../android/quickstep/views/RecentsView.java | 94 +++++++++++++++++++ src/com/android/launcher3/PagedView.java | 1 - 8 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 quickstep/res/drawable/ic_empty_recents.xml diff --git a/quickstep/res/drawable/ic_empty_recents.xml b/quickstep/res/drawable/ic_empty_recents.xml new file mode 100644 index 0000000000..5183733975 --- /dev/null +++ b/quickstep/res/drawable/ic_empty_recents.xml @@ -0,0 +1,30 @@ + + + + diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index b751e0d9c9..e354193102 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -36,4 +36,8 @@ 140dp 80dp 150% + + 16sp + 16dp + diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index c36e1ff18d..bd37a06aed 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -32,4 +32,7 @@ Overview + + + No recent items \ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index d8f206c5ed..5f94bcaf1f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -56,6 +56,7 @@ public class RecentsViewStateController implements StateHandler { mRecentsView.setTranslationXFactor(translationFactor[0]); mRecentsView.setTranslationYFactor(translationFactor[1]); if (state.overviewUi) { + mRecentsView.updateEmptyMessage(); mRecentsView.resetTaskVisuals(); } } @@ -94,6 +95,7 @@ public class RecentsViewStateController implements StateHandler { }); updateAnim.setDuration(config.duration); builder.play(updateAnim); + mRecentsView.updateEmptyMessage(); } } } diff --git a/quickstep/src/com/android/quickstep/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/FallbackRecentsView.java index 032d753a68..251e958063 100644 --- a/quickstep/src/com/android/quickstep/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/FallbackRecentsView.java @@ -16,8 +16,10 @@ package com.android.quickstep; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; +import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; @@ -32,6 +34,7 @@ public class FallbackRecentsView extends RecentsView implements public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setOverviewStateEnabled(true); + updateEmptyMessage(); } @Override @@ -39,6 +42,18 @@ public class FallbackRecentsView extends RecentsView implements mActivity.finish(); } + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + updateEmptyMessage(); + } + + @Override + public void onViewRemoved(View child) { + super.onViewRemoved(child); + updateEmptyMessage(); + } + @Override public void setInsets(Rect insets) { mInsets.set(insets); @@ -65,4 +80,10 @@ public class FallbackRecentsView extends RecentsView implements grid.widthPx - targetPadding.right - insets.right, grid.heightPx - targetPadding.bottom - insets.bottom); } + + @Override + public void draw(Canvas canvas) { + maybeDrawEmptyMessage(canvas); + super.draw(canvas); + } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 861b5fa038..34c3e4f05c 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -19,10 +19,12 @@ import static com.android.launcher3.LauncherState.NORMAL; import android.annotation.TargetApi; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.util.FloatProperty; +import android.view.View; import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; @@ -103,19 +105,12 @@ public class LauncherRecentsView extends RecentsView implements Insett @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - - int width = right - left; - setTranslationX(mTranslationXFactor * (mIsRtl ? -width : width)); setTranslationYFactor(mTranslationYFactor); } public void setTranslationXFactor(float translationFactor) { mTranslationXFactor = translationFactor; - setTranslationX(translationFactor * (mIsRtl ? -getWidth() : getWidth())); - } - - public float getTranslationXFactor() { - return mTranslationXFactor; + invalidate(); } public void setTranslationYFactor(float translationFactor) { @@ -123,7 +118,24 @@ public class LauncherRecentsView extends RecentsView implements Insett setTranslationY(mTranslationYFactor * (mPagePadding.bottom - mPagePadding.top)); } - public float getTranslationYFactor() { - return mTranslationYFactor; + @Override + public void draw(Canvas canvas) { + maybeDrawEmptyMessage(canvas); + int count = canvas.save(); + canvas.translate(mTranslationXFactor * (mIsRtl ? -getWidth() : getWidth()), 0); + super.draw(canvas); + canvas.restoreToCount(count); + } + + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + updateEmptyMessage(); + } + + @Override + protected void onTaskStackUpdated() { + // Lazily update the empty message only when the task stack is reapplied + updateEmptyMessage(); } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 8901e6d8c6..f75d6bcf78 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -29,8 +29,14 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.graphics.Canvas; +import android.graphics.Point; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; import android.util.ArraySet; import android.util.AttributeSet; import android.util.FloatProperty; @@ -46,6 +52,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.util.Themes; import com.android.quickstep.PendingAnimation; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsModel; @@ -130,6 +137,15 @@ public abstract class RecentsView // Keeps track of task views whose visual state should not be reset private ArraySet mIgnoreResetTaskViews = new ArraySet<>(); + // Variables for empty state + private final Drawable mEmptyIcon; + private final CharSequence mEmptyMessage; + private final TextPaint mEmptyMessagePaint; + private final Point mLastMeasureSize = new Point(); + private final int mEmptyMessagePadding; + private boolean mShowEmptyMessage; + private Layout mEmptyTextLayout; + public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing)); @@ -143,6 +159,17 @@ public abstract class RecentsView mModel = RecentsModel.getInstance(context); onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS); + + mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents); + mEmptyIcon.setCallback(this); + mEmptyMessage = context.getText(R.string.recents_empty_message); + mEmptyMessagePaint = new TextPaint(); + mEmptyMessagePaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary)); + mEmptyMessagePaint.setTextSize(getResources() + .getDimension(R.dimen.recents_empty_message_text_size)); + mEmptyMessagePadding = getResources() + .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding); + setWillNotDraw(false); } @Override @@ -247,6 +274,7 @@ public abstract class RecentsView TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; if (stack == null) { removeAllViews(); + onTaskStackUpdated(); return; } @@ -283,8 +311,11 @@ public abstract class RecentsView if (oldChildCount != getChildCount()) { mQuickScrubController.snapToNextTaskIfAvailable(); } + onTaskStackUpdated(); } + protected void onTaskStackUpdated() { } + public void resetTaskVisuals() { for (int i = getChildCount() - 1; i >= 0; i--) { TaskView taskView = (TaskView) getChildAt(i); @@ -700,6 +731,11 @@ public abstract class RecentsView for (int i = getChildCount() - 1; i >= 0; i--) { getChildAt(i).setAlpha(alpha); } + + int alphaInt = Math.round(alpha * 255); + mEmptyMessagePaint.setAlpha(alphaInt); + mEmptyIcon.setAlpha(alphaInt); + setVisibility(alpha > 0 ? VISIBLE : GONE); } @@ -708,4 +744,62 @@ public abstract class RecentsView super.onViewAdded(child); child.setAlpha(mContentAlpha); } + + public void updateEmptyMessage() { + boolean isEmpty = getChildCount() == 0; + boolean hasSizeChanged = mLastMeasureSize.x != getWidth() + || mLastMeasureSize.y != getHeight(); + if (isEmpty == mShowEmptyMessage && !hasSizeChanged) { + return; + } + setContentDescription(isEmpty ? mEmptyMessage : ""); + mShowEmptyMessage = isEmpty; + updateEmptyStateUi(hasSizeChanged); + invalidate(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateEmptyStateUi(changed); + } + + private void updateEmptyStateUi(boolean sizeChanged) { + boolean hasValidSize = getWidth() > 0 && getHeight() > 0; + if (sizeChanged && hasValidSize) { + mEmptyTextLayout = null; + } + + if (mShowEmptyMessage && hasValidSize && mEmptyTextLayout == null) { + mLastMeasureSize.set(getWidth(), getHeight()); + int availableWidth = mLastMeasureSize.x - mEmptyMessagePadding - mEmptyMessagePadding; + mEmptyTextLayout = StaticLayout.Builder.obtain(mEmptyMessage, 0, mEmptyMessage.length(), + mEmptyMessagePaint, availableWidth) + .setAlignment(Layout.Alignment.ALIGN_CENTER) + .build(); + int totalHeight = mEmptyTextLayout.getHeight() + + mEmptyMessagePadding + mEmptyIcon.getIntrinsicHeight(); + + int top = (mLastMeasureSize.y - totalHeight) / 2; + int left = (mLastMeasureSize.x - mEmptyIcon.getIntrinsicWidth()) / 2; + mEmptyIcon.setBounds(left, top, left + mEmptyIcon.getIntrinsicWidth(), + top + mEmptyIcon.getIntrinsicHeight()); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || (mShowEmptyMessage && who == mEmptyIcon); + } + + protected void maybeDrawEmptyMessage(Canvas canvas) { + if (mShowEmptyMessage && mEmptyTextLayout != null) { + mEmptyIcon.draw(canvas); + canvas.save(); + canvas.translate(mEmptyMessagePadding, + mEmptyIcon.getBounds().bottom + mEmptyMessagePadding); + mEmptyTextLayout.draw(canvas); + canvas.restore(); + } + } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index a1ac122d87..1e761e41d4 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -187,7 +187,6 @@ public abstract class PagedView extends ViewGrou mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * density); mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * density); mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density); - setWillNotDraw(false); if (Utilities.ATLEAST_OREO) { setDefaultFocusHighlightEnabled(false); From 61857f3f39c8a5f476e416795de247020751f72f Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 23 Mar 2018 13:48:03 -0700 Subject: [PATCH 05/81] Prevent edge gradient for screenshots in correct orientation - Due to rounding issues, the width could be a pixel too small, causing a gradient on the right edge - On tall devices, the height ratio of the task thumbnail might be larger than the width ratio, causing the screenshot to be too short upon swiping up, and thus a gradient on the bottom edge Bug: 73540853 Change-Id: I1330cec3d2ff8c98eb1b354f0e7f40c6ea49ad7c --- .../android/quickstep/views/RecentsView.java | 20 +++++++++++++++++++ .../quickstep/views/TaskThumbnailView.java | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index db82286079..d5c0ff8b85 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -323,11 +323,31 @@ public abstract class RecentsView padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top - Math.round(overviewHeight); padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2); + + // If the height ratio is larger than the width ratio, the screenshot will get cropped + // at the bottom when swiping up. In this case, increase the top/bottom padding to make it + // the same aspect ratio. + Rect pageRect = new Rect(); + getPageRect(profile, context, pageRect, padding); + float widthRatio = (float) pageRect.width() / taskWidth; + float heightRatio = (float) pageRect.height() / taskHeight; + if (heightRatio > widthRatio) { + float additionalVerticalPadding = pageRect.height() - widthRatio * taskHeight; + additionalVerticalPadding = Math.round(additionalVerticalPadding); + padding.top += additionalVerticalPadding / 2; + padding.bottom += additionalVerticalPadding / 2; + } + return padding; } public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) { Rect targetPadding = getPadding(grid, context); + getPageRect(grid, context, outRect, targetPadding); + } + + private static void getPageRect(DeviceProfile grid, Context context, Rect outRect, + Rect targetPadding) { Rect insets = grid.getInsets(); outRect.set( targetPadding.left + insets.left, diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 87bb53bb61..6f8878c2cc 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -175,7 +175,7 @@ public class TaskThumbnailView extends View { float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); Shader shader = mBitmapShader; - if (bitmapHeight < getMeasuredHeight()) { + if (Math.round(bitmapHeight) < getMeasuredHeight()) { int color = mPaint.getColor(); LinearGradient fade = new LinearGradient( 0, bitmapHeight - mFadeLength, 0, bitmapHeight, @@ -184,7 +184,7 @@ public class TaskThumbnailView extends View { } float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0); - if (bitmapWidth < getMeasuredWidth()) { + if (Math.round(bitmapWidth) < getMeasuredWidth()) { int color = mPaint.getColor(); LinearGradient fade = new LinearGradient( bitmapWidth - mFadeLength, 0, bitmapWidth, 0, From 20bfde36007402f958767371fe16b1ac89191871 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 26 Mar 2018 17:18:36 -0700 Subject: [PATCH 06/81] Show overview tiles in the orientation screenshot was taken If the orientation of the screenshot doesn't match the thumbnail view, we rotate the screenshot 90 degrees. We don't know whether a landscape screenshot was seascape, so we just assume it's not (i.e. landscape screenshots always rotate +90 degrees when shown in portrait). Portrait screenshots rotate so that the bottom aligns with the nav bar, e.g. rotate +90 in seascape and -90 in landscape Currently guarded by the flag OVERVIEW_USE_SCREENSHOT_ORIENTATION. Bug: 74552612 Change-Id: I438e45d89b54ffe41950c8bb9abdbb9a1c33aa40 --- .../quickstep/views/TaskThumbnailView.java | 82 +++++++++++++------ .../android/launcher3/config/BaseFlags.java | 4 + 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 6f8878c2cc..e443eeab36 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -36,6 +36,7 @@ import android.view.View; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.config.FeatureFlags; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; @@ -146,6 +147,9 @@ public class TaskThumbnailView extends View { (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale; final float thumbnailScale; + boolean rotate = false; + final DeviceProfile profile = BaseActivity.fromContext(getContext()) + .getDeviceProfile(); if (getMeasuredWidth() == 0) { // If we haven't measured , skip the thumbnail drawing and only draw the background // color @@ -153,43 +157,71 @@ public class TaskThumbnailView extends View { } else { final Configuration configuration = getContext().getApplicationContext().getResources().getConfiguration(); - final DeviceProfile profile = BaseActivity.fromContext(getContext()) - .getDeviceProfile(); if (configuration.orientation == mThumbnailData.orientation) { // If we are in the same orientation as the screenshot, just scale it to the // width of the task view thumbnailScale = getMeasuredWidth() / thumbnailWidth; - } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { - // Scale the landscape thumbnail up to app size, then scale that to the task - // view size to match other portrait screenshots - thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx); } else { - // Otherwise, scale the screenshot to fit 1:1 in the current orientation - thumbnailScale = 1; + if (FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION) { + rotate = true; + // Scale the height (will be width after rotation) to the width of this view + thumbnailScale = getMeasuredWidth() / thumbnailHeight; + } else { + if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { + // Scale the landscape thumbnail up to app size, then scale that to the + // task view size to match other portrait screenshots + thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx); + } else { + // Otherwise, scale the screenshot to fit 1:1 in the current orientation + thumbnailScale = 1; + } + } } } - mMatrix.setTranslate(-mThumbnailData.insets.left * scale, - -mThumbnailData.insets.top * scale); + if (rotate) { + int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1; + mMatrix.setRotate(90 * rotationDir); + Rect thumbnailInsets = mThumbnailData.insets; + int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top; + int newTopInset = rotationDir == 1 ? thumbnailInsets.left : thumbnailInsets.right; + mMatrix.postTranslate(-newLeftInset * scale, -newTopInset * scale); + if (rotationDir == -1) { + // Crop the right/bottom side of the screenshot rather than left/top + float excessHeight = thumbnailWidth * thumbnailScale - getMeasuredHeight(); + mMatrix.postTranslate(0, -excessHeight); + } + // Move the screenshot to the thumbnail window (rotation moved it out). + if (rotationDir == 1) { + mMatrix.postTranslate(mThumbnailData.thumbnail.getHeight(), 0); + } else { + mMatrix.postTranslate(0, mThumbnailData.thumbnail.getWidth()); + } + } else { + mMatrix.setTranslate(-mThumbnailData.insets.left * scale, + -mThumbnailData.insets.top * scale); + } mMatrix.postScale(thumbnailScale, thumbnailScale); mBitmapShader.setLocalMatrix(mMatrix); - float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); Shader shader = mBitmapShader; - if (Math.round(bitmapHeight) < getMeasuredHeight()) { - int color = mPaint.getColor(); - LinearGradient fade = new LinearGradient( - 0, bitmapHeight - mFadeLength, 0, bitmapHeight, - color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); - shader = new ComposeShader(fade, shader, Mode.DST_OVER); - } + if (!FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION) { + float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); + if (Math.round(bitmapHeight) < getMeasuredHeight()) { + int color = mPaint.getColor(); + LinearGradient fade = new LinearGradient( + 0, bitmapHeight - mFadeLength, 0, bitmapHeight, + color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); + shader = new ComposeShader(fade, shader, Mode.DST_OVER); + } - float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0); - if (Math.round(bitmapWidth) < getMeasuredWidth()) { - int color = mPaint.getColor(); - LinearGradient fade = new LinearGradient( - bitmapWidth - mFadeLength, 0, bitmapWidth, 0, - color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); - shader = new ComposeShader(fade, shader, Mode.DST_OVER); + float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0); + if (Math.round(bitmapWidth) < getMeasuredWidth()) { + int color = mPaint.getColor(); + LinearGradient fade = new LinearGradient( + bitmapWidth - mFadeLength, 0, bitmapWidth, 0, + color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); + shader = new ComposeShader(fade, shader, Mode.DST_OVER); + } } mPaint.setShader(shader); } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 78ea419b82..f4c6380b74 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -51,4 +51,8 @@ abstract class BaseFlags { // When enabled shows a work profile tab in all apps public static final boolean ALL_APPS_TABS_ENABLED = true; + + // When true, overview shows screenshots in the orientation they were taken rather than + // trying to make them fit the orientation the device is in. + public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true; } From ef77fd0f40ac8b7564dfd7ce5ebea7f31e194315 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 21 Mar 2018 16:28:59 -0700 Subject: [PATCH 07/81] Workaround for ensuring dummy task view has valid task - Always assign the first task the running task id so that we can still identify it if applyLoadPlan() is not yet called back from loading tasks. Bug: 76100710 Change-Id: I22e2948a67f532b60415a248d6121febba29b3f6 --- .../android/quickstep/views/RecentsView.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 41ac6b1abf..bc4cd90baf 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -26,7 +26,10 @@ import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.graphics.Canvas; @@ -123,6 +126,7 @@ public abstract class RecentsView // Only valid until the launcher state changes to NORMAL private int mRunningTaskId = -1; + private Task mTmpRunningTask; private boolean mFirstTaskIconScaledDown = false; @@ -470,6 +474,10 @@ public abstract class RecentsView Task task = taskView.getTask(); boolean visible = lower <= i && i <= upper; if (visible) { + if (task == mTmpRunningTask) { + // Skip loading if this is the task that we are animating into + continue; + } if (!mHasVisibleTaskData.get(task.key.id)) { loader.loadTaskData(task); loader.getHighResThumbnailLoader().onTaskVisible(task); @@ -528,24 +536,27 @@ public abstract class RecentsView * Also scrolls the view to this task */ public void showTask(int runningTaskId) { - boolean needsReload = false; if (getChildCount() == 0) { - needsReload = true; - // Add an empty view for now + // Add an empty view for now until the task plan is loaded and applied final TaskView taskView = (TaskView) LayoutInflater.from(getContext()) .inflate(R.layout.task, this, false); - addView(taskView, 0); + addView(taskView); + + // The temporary running task is only used for the duration between the start of the + // gesture and the task list is loaded and applied + mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(), 0, 0), null, + null, "", "", 0, 0, false, true, false, false, + new ActivityManager.TaskDescription(), 0, new ComponentName("", ""), false); + taskView.bind(mTmpRunningTask); } + mRunningTaskId = runningTaskId; setCurrentPage(0); - if (!needsReload) { - needsReload = !mModel.isLoadPlanValid(mLoadPlanId); - } - if (needsReload) { - mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); - } else { - loadVisibleTaskData(); - } + + // Load the tasks (if the loading is already + mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); + + // Hide the task that we are animating into getPageAt(mCurrentPage).setAlpha(0); } From 314ab5d6b5ffb9070e4a4235b186d589a880e3f1 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 27 Mar 2018 11:48:37 -0700 Subject: [PATCH 08/81] Raise char limit from 100 to 200 on accessibility string. Bug: 76444955 Change-Id: I44a168bd9705ca8ab37f98a41aae0dceb5d9536a --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 7d5d81c60e..bcb90e3fdf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -74,7 +74,7 @@ Touch & hold to pick up a shortcut. - + Double-tap & hold to pick up a shortcut or use custom actions. From 5ab0d896c6636276976e75cbe549db8eb1232ef3 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 26 Mar 2018 17:30:50 -0700 Subject: [PATCH 09/81] Send directed broadcast to package installers that have active sessions. For each installer, we send a broadcast that includes package names of items that: * Are being installed by that installer * Are on the first screen * Have an active install session The packages are seperated by: * Folder items * Workspace items * Hotseat items * Widgets Bug: 74355094 Change-Id: I573ed6b3b84314ef244486fcf8354bebdff8bbdf --- .../compat/PackageInstallerCompat.java | 2 +- .../compat/PackageInstallerCompatVL.java | 6 +- .../launcher3/model/FirstScreenBroadcast.java | 164 ++++++++++++++++++ .../launcher3/model/LoaderResults.java | 2 +- .../android/launcher3/model/LoaderTask.java | 41 ++++- 5 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 src/com/android/launcher3/model/FirstScreenBroadcast.java diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java index 112cca5402..3270ba2005 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompat.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java @@ -45,7 +45,7 @@ public abstract class PackageInstallerCompat { /** * @return a map of active installs to their progress */ - public abstract HashMap updateAndGetActiveSessionCache(); + public abstract HashMap updateAndGetActiveSessionCache(); public abstract void onStop(); diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java index 1ffd3da014..dd17916f0d 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java @@ -59,13 +59,13 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { } @Override - public HashMap updateAndGetActiveSessionCache() { - HashMap activePackages = new HashMap<>(); + public HashMap updateAndGetActiveSessionCache() { + HashMap activePackages = new HashMap<>(); UserHandle user = Process.myUserHandle(); for (SessionInfo info : getAllVerifiedSessions()) { addSessionInfoToCache(info, user); if (info.getAppPackageName() != null) { - activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100)); + activePackages.put(info.getAppPackageName(), info); mActiveSessions.put(info.getSessionId(), info.getAppPackageName()); } } diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java new file mode 100644 index 0000000000..2736509ca6 --- /dev/null +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 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.model; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInstaller.SessionInfo; +import android.util.Log; + +import com.android.launcher3.FolderInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.util.MultiHashMap; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Helper class to send broadcasts to package installers that have: + * - Items on the first screen + * - Items with an active install session + * + * The packages are broken down by: folder items, workspace items, hotseat items, and widgets. + * + * Package installers only receive data for items that they are installing. + */ +public class FirstScreenBroadcast { + + private static final String TAG = "FirstScreenBroadcast"; + private static final boolean DEBUG = false; + + private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS + = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS"; + + private static final String FOLDER_ITEM_EXTRA = "folderItem"; + private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem"; + private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem"; + private static final String WIDGET_ITEM_EXTRA = "widgetItem"; + + private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken"; + + private final MultiHashMap mPackagesForInstaller; + + public FirstScreenBroadcast(HashMap sessionInfoForPackage) { + mPackagesForInstaller = getPackagesForInstaller(sessionInfoForPackage); + } + + /** + * @return Map where the key is the package name of the installer, and the value is a list + * of packages with active sessions for that installer. + */ + private MultiHashMap getPackagesForInstaller( + HashMap sessionInfoForPackage) { + MultiHashMap packagesForInstaller = new MultiHashMap<>(); + for (Map.Entry entry : sessionInfoForPackage.entrySet()) { + packagesForInstaller.addToList(entry.getValue().getInstallerPackageName(), + entry.getKey()); + } + return packagesForInstaller; + } + + /** + * Sends a broadcast to all package installers that have items with active sessions on the users + * first screen. + */ + public void sendBroadcasts(Context context, List firstScreenItems) { + for (Map.Entry> entry : mPackagesForInstaller.entrySet()) { + sendBroadcastToInstaller(context, entry.getKey(), entry.getValue(), firstScreenItems); + } + } + + /** + * @param installerPackageName Package name of the package installer. + * @param packages List of packages with active sessions for this package installer. + * @param firstScreenItems List of items on the first screen. + */ + private void sendBroadcastToInstaller(Context context, String installerPackageName, + List packages, List firstScreenItems) { + Set folderItems = new HashSet<>(); + Set workspaceItems = new HashSet<>(); + Set hotseatItems = new HashSet<>(); + Set widgetItems = new HashSet<>(); + + for (ItemInfo info : firstScreenItems) { + if (info instanceof FolderInfo) { + FolderInfo folderInfo = (FolderInfo) info; + String folderItemInfoPackage; + for (ItemInfo folderItemInfo : folderInfo.contents) { + folderItemInfoPackage = getPackageName(folderItemInfo); + if (folderItemInfoPackage != null + && packages.contains(folderItemInfoPackage)) { + folderItems.add(folderItemInfoPackage); + } + } + } + + String packageName = getPackageName(info); + if (packageName == null || !packages.contains(packageName)) { + continue; + } + if (info instanceof LauncherAppWidgetInfo) { + widgetItems.add(packageName); + } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + hotseatItems.add(packageName); + } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + workspaceItems.add(packageName); + } + } + + if (DEBUG) { + printList(installerPackageName, "Folder item", folderItems); + printList(installerPackageName, "Workspace item", workspaceItems); + printList(installerPackageName, "Hotseat item", hotseatItems); + printList(installerPackageName, "Widget item", widgetItems); + } + + context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS) + .setPackage(installerPackageName) + .putExtra(FOLDER_ITEM_EXTRA, folderItems.toArray()) + .putExtra(WORKSPACE_ITEM_EXTRA, workspaceItems.toArray()) + .putExtra(HOTSEAT_ITEM_EXTRA, hotseatItems.toArray()) + .putExtra(WIDGET_ITEM_EXTRA, widgetItems.toArray()) + .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0, + new Intent(), PendingIntent.FLAG_ONE_SHOT))); + } + + private static String getPackageName(ItemInfo info) { + String packageName = null; + if (info instanceof LauncherAppWidgetInfo) { + LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info; + if (widgetInfo.providerName != null) { + packageName = widgetInfo.providerName.getPackageName(); + } + } else if (info.getTargetComponent() != null){ + packageName = info.getTargetComponent().getPackageName(); + } + return packageName; + } + + private static void printList(String packageInstaller, String label, Set packages) { + for (String pkg : packages) { + Log.d(TAG, packageInstaller + ":" + label + ":" + pkg); + } + } +} diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java index 5d4a352994..0fd9b735ed 100644 --- a/src/com/android/launcher3/model/LoaderResults.java +++ b/src/com/android/launcher3/model/LoaderResults.java @@ -209,7 +209,7 @@ public class LoaderResults { /** Filters the set of items who are directly or indirectly (via another container) on the * specified screen. */ - private void filterCurrentWorkspaceItems(long currentScreenId, + public static void filterCurrentWorkspaceItems(long currentScreenId, ArrayList allWorkspaceItems, ArrayList currentScreenItems, ArrayList otherScreenItems) { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 9d1ff83168..06da843f7f 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -20,6 +20,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER; import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE; import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW; +import static com.android.launcher3.model.LoaderResults.filterCurrentWorkspaceItems; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; @@ -29,6 +30,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; import android.graphics.Bitmap; import android.os.Handler; import android.os.Process; @@ -92,6 +94,8 @@ public class LoaderTask implements Runnable { private final AllAppsList mBgAllAppsList; private final BgDataModel mBgDataModel; + private FirstScreenBroadcast mFirstScreenBroadcast; + private final LoaderResults mResults; private final LauncherAppsCompat mLauncherApps; @@ -134,6 +138,22 @@ public class LoaderTask implements Runnable { } } + private void sendFirstScreenActiveInstallsBroadcast() { + ArrayList firstScreenItems = new ArrayList<>(); + + ArrayList allItems = new ArrayList<>(); + synchronized (mBgDataModel) { + allItems.addAll(mBgDataModel.workspaceItems); + allItems.addAll(mBgDataModel.appWidgets); + } + long firstScreen = mBgDataModel.workspaceScreens.isEmpty() + ? -1 // In this case, we can still look at the items in the hotseat. + : mBgDataModel.workspaceScreens.get(0); + filterCurrentWorkspaceItems(firstScreen, allItems, firstScreenItems, + new ArrayList<>() /* otherScreenItems are ignored */); + mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems); + } + public void run() { synchronized (this) { // Skip fast if we are already stopped. @@ -151,6 +171,10 @@ public class LoaderTask implements Runnable { TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace"); mResults.bindWorkspace(); + // Notify the installer packages of packages with active installs on the first screen. + TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast"); + sendFirstScreenActiveInstallsBroadcast(); + // Take a break TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle"); waitForIdle(); @@ -242,8 +266,9 @@ public class LoaderTask implements Runnable { synchronized (mBgDataModel) { mBgDataModel.clear(); - final HashMap installingPkgs = + final HashMap installingPkgs = mPackageInstaller.updateAndGetActiveSessionCache(); + mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context)); Map shortcutKeyToPinnedShortcuts = new HashMap<>(); @@ -511,11 +536,11 @@ public class LoaderTask implements Runnable { } if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { - Integer progress = installingPkgs.get(targetPkg); - if (progress != null) { - info.setInstallProgress(progress); - } else { + SessionInfo si = installingPkgs.get(targetPkg); + if (si == null) { info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + } else { + info.setInstallProgress((int) (si.getProgress() * 100)); } } @@ -605,7 +630,11 @@ public class LoaderTask implements Runnable { appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component); appWidgetInfo.restoreStatus = c.restoreFlag; - Integer installProgress = installingPkgs.get(component.getPackageName()); + SessionInfo si = + installingPkgs.get(component.getPackageName()); + Integer installProgress = si == null + ? null + : (int) (si.getProgress() * 100); if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) { // Restore has started once. From a750730d9044b0c6b2358b0731b5f58d4c802b3f Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Mar 2018 20:09:50 +0000 Subject: [PATCH 10/81] Revert "Using dimension instead of relyong on relativeLayout for view positions" This reverts commit 9623ed1894829cb046db36c5bdab71d2bcc4bd51. Reason for revert: b/76398583 Change-Id: I85f842d2c1511fe7ac374756e83641b59cbdd56d --- res/layout/all_apps_fast_scroller.xml | 6 +++--- res/layout/all_apps_floating_header.xml | 6 +++--- res/layout/all_apps_rv_layout.xml | 2 +- res/layout/all_apps_tabs.xml | 3 ++- res/values/dimens.xml | 7 +------ 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml index d858d3e21a..5537bc60a5 100644 --- a/res/layout/all_apps_fast_scroller.xml +++ b/res/layout/all_apps_fast_scroller.xml @@ -21,8 +21,8 @@ android:id="@+id/fast_scroller_popup" style="@style/FastScrollerPopup" android:layout_alignParentEnd="true" - android:layout_marginEnd="@dimen/fastscroll_popup_margin" - android:layout_marginTop="@dimen/all_apps_search_bar_field_height_and_margin" /> + android:layout_below="@+id/search_container_all_apps" + android:layout_marginEnd="@dimen/fastscroll_popup_margin" /> \ No newline at end of file diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml index f88c600423..c4240f80db 100644 --- a/res/layout/all_apps_floating_header.xml +++ b/res/layout/all_apps_floating_header.xml @@ -18,10 +18,10 @@ android:id="@+id/all_apps_header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/all_apps_search_bar_field_height_and_margin" + android:layout_below="@id/search_container_all_apps" android:clipToPadding="false" - android:orientation="vertical" - android:paddingTop="@dimen/all_apps_header_top_padding" > + android:paddingTop="@dimen/all_apps_header_top_padding" + android:orientation="vertical" > diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml index fea2eeae30..2accd2d21f 100644 --- a/res/layout/all_apps_tabs.xml +++ b/res/layout/all_apps_tabs.xml @@ -20,8 +20,9 @@ android:id="@+id/all_apps_tabs_view_pager" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_below="@id/search_container_all_apps" android:layout_gravity="center_horizontal|top" - android:layout_marginTop="@dimen/all_apps_tabs_top_margin" + android:layout_marginTop="@dimen/all_apps_header_tab_height" android:clipChildren="true" android:clipToPadding="false" android:descendantFocusability="afterDescendants" diff --git a/res/values/dimens.xml b/res/values/dimens.xml index b7e7ca1d2c..f8f9c2ae99 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -95,12 +95,7 @@ 8dp - - 56dp - - 106dp - - + 8dp 16dp From 85fd66800dbc4b6a2cdd1ce5b3d50a2e0a962865 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 27 Mar 2018 13:31:39 -0700 Subject: [PATCH 11/81] Fix divide by 0 Bug: 76392987 Change-Id: Ib55b3e47b296f4aaa690f7af83c5d92b242ed029 --- quickstep/src/com/android/quickstep/views/RecentsView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 41ac6b1abf..159ee1b99a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -680,6 +680,9 @@ public abstract class RecentsView } private void snapToPageRelative(int delta) { + if (getPageCount() == 0) { + return; + } snapToPage((getNextPage() + getPageCount() + delta) % getPageCount()); } From 5b70f5175024763eb8a9c9213048c0815814866f Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Mar 2018 15:50:04 -0700 Subject: [PATCH 12/81] Fixing wrong visibility being set for RecentsView Change-Id: I03890eabe80dd9339a3de9449772ab7fb36a6db1 --- .../launcher3/uioverrides/RecentsViewStateController.java | 3 --- .../src/com/android/quickstep/views/LauncherRecentsView.java | 4 ++++ quickstep/src/com/android/quickstep/views/RecentsView.java | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 5f94bcaf1f..9f7fef33d2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -16,10 +16,8 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATION; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_X_FACTOR; import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; @@ -51,7 +49,6 @@ public class RecentsViewStateController implements StateHandler { @Override public void setState(LauncherState state) { mRecentsView.setContentAlpha(state.overviewUi ? 1 : 0); - updateVisibility(mRecentsView, isAccessibilityEnabled(mLauncher)); float[] translationFactor = state.getOverviewTranslationFactor(mLauncher); mRecentsView.setTranslationXFactor(translationFactor[0]); mRecentsView.setTranslationYFactor(translationFactor[1]); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 34c3e4f05c..55ed9a941e 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -25,6 +25,7 @@ import android.os.Build; import android.util.AttributeSet; import android.util.FloatProperty; import android.view.View; +import android.view.ViewDebug; import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; @@ -66,8 +67,11 @@ public class LauncherRecentsView extends RecentsView implements Insett } }; + @ViewDebug.ExportedProperty(category = "launcher") private float mTranslationXFactor; + @ViewDebug.ExportedProperty(category = "launcher") private float mTranslationYFactor; + private Rect mPagePadding = new Rect(); public LauncherRecentsView(Context context) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 159ee1b99a..97f40bcc54 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -44,6 +44,7 @@ import android.util.SparseBooleanArray; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewDebug; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; @@ -132,6 +133,7 @@ public abstract class RecentsView private PendingAnimation mPendingAnimation; + @ViewDebug.ExportedProperty(category = "launcher") private float mContentAlpha = 1; // Keeps track of task views whose visual state should not be reset @@ -750,6 +752,7 @@ public abstract class RecentsView if (mContentAlpha == alpha) { return; } + mContentAlpha = alpha; for (int i = getChildCount() - 1; i >= 0; i--) { getChildAt(i).setAlpha(alpha); From e7a49dc915958b0aef9ed0351ca28f448e65fdc0 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 27 Mar 2018 14:46:46 -0700 Subject: [PATCH 13/81] Don't add task overlay when thumbnail is rotated Change-Id: Ie4088c8c1a1c22a30caddc5bfb6b76e6a42ef088 --- .../com/android/quickstep/views/TaskThumbnailView.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index e443eeab36..4c8d69f684 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -139,6 +139,7 @@ public class TaskThumbnailView extends View { } private void updateThumbnailMatrix() { + boolean rotate = false; if (mBitmapShader != null && mThumbnailData != null) { float scale = mThumbnailData.scale; float thumbnailWidth = mThumbnailData.thumbnail.getWidth() - @@ -146,8 +147,6 @@ public class TaskThumbnailView extends View { float thumbnailHeight = mThumbnailData.thumbnail.getHeight() - (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale; final float thumbnailScale; - - boolean rotate = false; final DeviceProfile profile = BaseActivity.fromContext(getContext()) .getDeviceProfile(); if (getMeasuredWidth() == 0) { @@ -226,7 +225,12 @@ public class TaskThumbnailView extends View { mPaint.setShader(shader); } - mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix); + if (rotate) { + // The overlay doesn't really work when the screenshot is rotated, so don't add it. + mOverlay.reset(); + } else { + mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix); + } invalidate(); } From fbcd52f407c99d059b5adca19f72dd20df07bd2f Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Mar 2018 20:40:28 -0700 Subject: [PATCH 14/81] Using the application classloader for unmarsheling internal classes Android default classloader may not find the custom classes defined in the launcher package, causing ClassNotFoundException Bug: 74234914 Change-Id: I47cc1034c699a1466da51137c4efd7a5c12af2fc --- src/com/android/launcher3/util/PendingRequestArgs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java index dabd40df12..b8bcfeda85 100644 --- a/src/com/android/launcher3/util/PendingRequestArgs.java +++ b/src/com/android/launcher3/util/PendingRequestArgs.java @@ -57,7 +57,7 @@ public class PendingRequestArgs extends ItemInfo implements Parcelable { mArg1 = parcel.readInt(); mObjectType = parcel.readInt(); - mObject = parcel.readParcelable(null); + mObject = parcel.readParcelable(getClass().getClassLoader()); } @Override From 18d718492a11b838be91aab34952866b285ed0ee Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Mar 2018 13:44:00 -0700 Subject: [PATCH 15/81] Removing accessibility workaround for changing View visibility Original change-id: I9a687a39a358441afd57c0c46b57399ecbf23c36 Bug: 76418647 Change-Id: I0800bd4f521e052f0a1229fe6b7ceafd1b0429ae --- src/com/android/launcher3/DropTargetBar.java | 3 +- .../launcher3/anim/AlphaUpdateListener.java | 42 +++++++------------ .../launcher3/anim/PropertySetter.java | 7 +--- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java index dec6cb452e..d025a9b992 100644 --- a/src/com/android/launcher3/DropTargetBar.java +++ b/src/com/android/launcher3/DropTargetBar.java @@ -20,7 +20,6 @@ import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT; import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT; import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT; import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility; -import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import android.animation.TimeInterpolator; import android.content.Context; @@ -47,7 +46,7 @@ public class DropTargetBar extends FrameLayout protected static final TimeInterpolator DEFAULT_INTERPOLATOR = Interpolators.ACCEL; private final Runnable mFadeAnimationEndRunnable = - () -> updateVisibility(DropTargetBar.this, isAccessibilityEnabled(getContext())); + () -> updateVisibility(DropTargetBar.this); @ViewDebug.ExportedProperty(category = "launcher") protected boolean mDeferOnDragEnd; diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java index 04d97a7282..a3d02d9492 100644 --- a/src/com/android/launcher3/anim/AlphaUpdateListener.java +++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java @@ -17,7 +17,6 @@ package com.android.launcher3.anim; import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.view.View; @@ -25,44 +24,24 @@ import android.view.View; /** * A convenience class to update a view's visibility state after an alpha animation. */ -public class AlphaUpdateListener extends AnimatorListenerAdapter implements AnimatorUpdateListener { +public class AlphaUpdateListener extends AnimationSuccessListener + implements AnimatorUpdateListener { private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; private View mView; - private boolean mAccessibilityEnabled; - private boolean mCanceled = false; - public AlphaUpdateListener(View v, boolean accessibilityEnabled) { + public AlphaUpdateListener(View v) { mView = v; - mAccessibilityEnabled = accessibilityEnabled; } @Override public void onAnimationUpdate(ValueAnimator arg0) { - updateVisibility(mView, mAccessibilityEnabled); - } - - public static void updateVisibility(View view, boolean accessibilityEnabled) { - // We want to avoid the extra layout pass by setting the views to GONE unless - // accessibility is on, in which case not setting them to GONE causes a glitch. - int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE; - if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) { - view.setVisibility(invisibleState); - } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD - && view.getVisibility() != View.VISIBLE) { - view.setVisibility(View.VISIBLE); - } + updateVisibility(mView); } @Override - public void onAnimationCancel(Animator animation) { - mCanceled = true; - } - - @Override - public void onAnimationEnd(Animator arg0) { - if (mCanceled) return; - updateVisibility(mView, mAccessibilityEnabled); + public void onAnimationSuccess(Animator animator) { + updateVisibility(mView); } @Override @@ -70,4 +49,13 @@ public class AlphaUpdateListener extends AnimatorListenerAdapter implements Anim // We want the views to be visible for animation, so fade-in/out is visible mView.setVisibility(View.VISIBLE); } + + public static void updateVisibility(View view) { + if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != View.INVISIBLE) { + view.setVisibility(View.INVISIBLE); + } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD + && view.getVisibility() != View.VISIBLE) { + view.setVisibility(View.VISIBLE); + } + } } \ No newline at end of file diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java index 1f11f7e631..757edff74d 100644 --- a/src/com/android/launcher3/anim/PropertySetter.java +++ b/src/com/android/launcher3/anim/PropertySetter.java @@ -16,8 +16,6 @@ package com.android.launcher3.anim; -import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; - import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; @@ -34,7 +32,7 @@ public class PropertySetter { public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { if (view != null) { view.setAlpha(alpha); - AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext())); + AlphaUpdateListener.updateVisibility(view); } } @@ -64,8 +62,7 @@ public class PropertySetter { return; } ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha); - anim.addListener(new AlphaUpdateListener( - view, isAccessibilityEnabled(view.getContext()))); + anim.addListener(new AlphaUpdateListener(view)); anim.setDuration(mDuration).setInterpolator(interpolator); mStateAnimator.play(anim); } From 591e3608035da57b6839d09e588be02dab6b5eae Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 28 Mar 2018 11:37:00 -0700 Subject: [PATCH 16/81] Match folder icon size to normalized circle icon size. Simplifies the logic for calculating the folder icon size, and ensures consistent sizing in different launcher viewing modes. Bug: 74078689 Change-Id: I5cf4474fd81e55aa50b056418c95533801f07d48 --- res/values-land/dimens.xml | 3 --- res/values/dimens.xml | 2 -- src/com/android/launcher3/DeviceProfile.java | 9 ++++----- .../android/launcher3/folder/PreviewBackground.java | 11 ++++------- .../android/launcher3/graphics/IconNormalizer.java | 8 ++++++++ 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml index 6cf23ad10a..7b5252949a 100644 --- a/res/values-land/dimens.xml +++ b/res/values-land/dimens.xml @@ -31,9 +31,6 @@ 0dp 5.5dp - - 2dp - 0dp diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f8f9c2ae99..a2f7286794 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -137,8 +137,6 @@ 1dp - - 10dp 8dp 9dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 14d8b93da8..6f35752601 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -28,6 +28,7 @@ import android.util.DisplayMetrics; import com.android.launcher3.CellLayout.ContainerType; import com.android.launcher3.badge.BadgeRenderer; +import com.android.launcher3.graphics.IconNormalizer; public class DeviceProfile { @@ -81,9 +82,8 @@ public class DeviceProfile { public int workspaceCellPaddingXPx; // Folder - public int folderBackgroundOffset; public int folderIconSizePx; - public int folderIconPreviewPadding; + public int folderIconOffsetYPx; // Folder cell public int folderCellWidthPx; @@ -340,9 +340,8 @@ public class DeviceProfile { } // Folder icon - folderBackgroundOffset = -iconDrawablePaddingPx; - folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset; - folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding); + folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx); + folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; } private void updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res) { diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index a0912a4a06..069ec4ba11 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -129,18 +129,15 @@ public class PreviewBackground { }; public void setup(Launcher launcher, View invalidateDelegate, - int availableSpace, int topPadding) { + int availableSpaceX, int topPadding) { mInvalidateDelegate = invalidateDelegate; mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary); DeviceProfile grid = launcher.getDeviceProfile(); - final int previewSize = grid.folderIconSizePx; - final int previewPadding = grid.folderIconPreviewPadding; + previewSize = grid.folderIconSizePx; - this.previewSize = (previewSize - 2 * previewPadding); - - basePreviewOffsetX = (availableSpace - this.previewSize) / 2; - basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding; + basePreviewOffsetX = (availableSpaceX - previewSize) / 2; + basePreviewOffsetY = topPadding + grid.folderIconOffsetYPx; // Stroke width is 1dp mStrokeWidth = launcher.getResources().getDisplayMetrics().density; diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java index 5d99ba09ff..680c020228 100644 --- a/src/com/android/launcher3/graphics/IconNormalizer.java +++ b/src/com/android/launcher3/graphics/IconNormalizer.java @@ -376,4 +376,12 @@ public class IconNormalizer { last = i; } } + + /** + * @return The diameter of the normalized circle that fits inside of the square (size x size). + */ + public static int getNormalizedCircleSize(int size) { + float area = size * size * MAX_CIRCLE_AREA_FACTOR; + return (int) Math.round(Math.sqrt((4 * area) / Math.PI)); + } } From 75161b975072f02e4d1c1a5e26dbfaf76e0e34f4 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 28 Mar 2018 12:25:49 -0700 Subject: [PATCH 17/81] Pass intent extras as string arraylist. Bug: 74355094 Change-Id: I697d837e48d7de4a490d2ad74a9c1ec7987d0574 --- src/com/android/launcher3/model/FirstScreenBroadcast.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java index 2736509ca6..1149b553f6 100644 --- a/src/com/android/launcher3/model/FirstScreenBroadcast.java +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -135,10 +135,10 @@ public class FirstScreenBroadcast { context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS) .setPackage(installerPackageName) - .putExtra(FOLDER_ITEM_EXTRA, folderItems.toArray()) - .putExtra(WORKSPACE_ITEM_EXTRA, workspaceItems.toArray()) - .putExtra(HOTSEAT_ITEM_EXTRA, hotseatItems.toArray()) - .putExtra(WIDGET_ITEM_EXTRA, widgetItems.toArray()) + .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems)) + .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems)) + .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems)) + .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems)) .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_ONE_SHOT))); } From 32e634a7f46aae74266a2ad642b4482bf560c13f Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Wed, 28 Mar 2018 14:02:24 -0700 Subject: [PATCH 18/81] Enabling opening Overview via Alt-Tab by default Now that it's sufficiently implemented. Bug: 77218050 Bug: 73090995 Test: Open Overview vial Alt-tab Change-Id: I684f1d642a7d63e0bf9b6e1b537e7484ede23ed1 --- .../quickstep/TouchInteractionService.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index cc49dc743e..4aecc27259 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -61,8 +61,6 @@ import com.android.systemui.shared.system.NavigationBarCompat.HitTarget; @TargetApi(Build.VERSION_CODES.O) public class TouchInteractionService extends Service { - public static final boolean DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB = false; - private static final SparseArray sMotionEventNames; static { @@ -133,21 +131,17 @@ public class TouchInteractionService extends Service { @Override public void onOverviewShown(boolean triggeredFromAltTab) { - if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) { - if (triggeredFromAltTab) { - setupTouchConsumer(HIT_TARGET_NONE); - mEventQueue.onOverviewShownFromAltTab(); - } + if (triggeredFromAltTab) { + setupTouchConsumer(HIT_TARGET_NONE); + mEventQueue.onOverviewShownFromAltTab(); } } @Override public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { - if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) { - if (triggeredFromAltTab && !triggeredFromHomeKey) { - // onOverviewShownFromAltTab initiates quick scrub. Ending it here. - mEventQueue.onQuickScrubEnd(); - } + if (triggeredFromAltTab && !triggeredFromHomeKey) { + // onOverviewShownFromAltTab initiates quick scrub. Ending it here. + mEventQueue.onQuickScrubEnd(); } } From 8c1a935a45fe434a3afca3d88a2cbc10403a59fd Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 28 Mar 2018 13:17:32 -0700 Subject: [PATCH 19/81] Don't wait until layout to calculate the scroll range State UI is based on scroll range, which is applied on insets change. So the scroll range should be updated as part of insets change, for the State UI to be applied properly Bug: 77220795 Change-Id: I839f89e4887d9731b1483135724227c4245a00a9 --- .../allapps/AllAppsTransitionController.java | 20 ++++----- .../launcher3/allapps/SearchUiManager.java | 17 -------- .../search/AppsSearchContainerLayout.java | 43 ++++++------------- 3 files changed, 22 insertions(+), 58 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index aafae10976..8788db4454 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -23,7 +23,6 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.R; -import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.PropertySetter; @@ -39,8 +38,7 @@ import com.android.launcher3.util.Themes; * If release velocity < THRES1, snap according to either top or bottom depending on whether it's * closer to top or closer to the page indicator. */ -public class AllAppsTransitionController - implements OnScrollRangeChangeListener, StateHandler, OnDeviceProfileChangeListener { +public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener { public static final Property ALL_APPS_PROGRESS = new Property(Float.class, "allAppsProgress") { @@ -71,11 +69,11 @@ public class AllAppsTransitionController private float mShiftRange; // changes depending on the orientation private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent - private static final float DEFAULT_SHIFT_RANGE = 10; + private float mScrollRangeDelta = 0; public AllAppsTransitionController(Launcher l) { mLauncher = l; - mShiftRange = DEFAULT_SHIFT_RANGE; + mShiftRange = mLauncher.getDeviceProfile().heightPx; mProgress = 1f; mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark); @@ -95,6 +93,7 @@ public class AllAppsTransitionController @Override public void onDeviceProfileChanged(DeviceProfile dp) { mIsVerticalLayout = dp.isVerticalBarLayout(); + setScrollRangeDelta(mScrollRangeDelta); if (mIsVerticalLayout) { mAppsView.setAlpha(1); @@ -205,13 +204,14 @@ public class AllAppsTransitionController public void setupViews(AllAppsContainerView appsView) { mAppsView = appsView; - mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this); } - @Override - public void onScrollRangeChanged(int scrollRange) { - mShiftRange = scrollRange; - setProgress(mProgress); + /** + * Updates the total scroll range but does not update the UI. + */ + public void setScrollRangeDelta(float delta) { + mScrollRangeDelta = delta; + mShiftRange = mLauncher.getDeviceProfile().heightPx - mScrollRangeDelta; } /** diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index d8568f8eaf..68193f5c1c 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -15,8 +15,6 @@ */ package com.android.launcher3.allapps; -import android.support.animation.SpringAnimation; -import android.support.annotation.NonNull; import android.view.KeyEvent; /** @@ -29,11 +27,6 @@ public interface SearchUiManager { */ void initialize(AllAppsContainerView containerView); - /** - * A {@link SpringAnimation} that will be used when the user flings. - */ - @NonNull SpringAnimation getSpringForFling(); - /** * Notifies the search manager to close any active search session. */ @@ -44,14 +37,4 @@ public interface SearchUiManager { * some UI beforehand. */ void preDispatchKeyEvent(KeyEvent keyEvent); - - void addOnScrollRangeChangeListener(OnScrollRangeChangeListener listener); - - /** - * Callback for listening to changes in the vertical scroll range when opening all-apps. - */ - interface OnScrollRangeChangeListener { - - void onScrollRangeChanged(int scrollRange); - } } diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index dd80dace34..ad61c55db7 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -23,10 +23,6 @@ import static com.android.launcher3.graphics.IconNormalizer.ICON_VISIBLE_AREA_FA import android.content.Context; import android.graphics.Rect; -import android.support.animation.FloatValueHolder; -import android.support.animation.SpringAnimation; -import android.support.animation.SpringForce; -import android.support.annotation.NonNull; import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; @@ -39,6 +35,7 @@ import android.view.ViewGroup.MarginLayoutParams; import com.android.launcher3.DeviceProfile; import com.android.launcher3.ExtendedEditText; +import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsContainerView; @@ -55,7 +52,7 @@ import java.util.ArrayList; */ public class AppsSearchContainerLayout extends ExtendedEditText implements SearchUiManager, AllAppsSearchBarController.Callbacks, - AllAppsStore.OnUpdateListener { + AllAppsStore.OnUpdateListener, Insettable { private final Launcher mLauncher; @@ -64,7 +61,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText private AlphabeticalAppsList mApps; private AllAppsContainerView mAppsView; - private SpringAnimation mSpring; public AppsSearchContainerLayout(Context context) { this(context, null); @@ -91,9 +87,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search), 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); setHint(spanned); - - // Note: This spring does nothing. - mSpring = new SpringAnimation(new FloatValueHolder()).setSpring(new SpringForce(0)); } @Override @@ -145,11 +138,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText new DefaultAppSearchAlgorithm(mApps.getApps()), this, mLauncher, this); } - @Override - public @NonNull SpringAnimation getSpringForFling() { - return mSpring; - } - @Override public void onAppsUpdated() { mSearchBarController.refreshSearchResult(); @@ -206,22 +194,15 @@ public class AppsSearchContainerLayout extends ExtendedEditText } @Override - public void addOnScrollRangeChangeListener(final OnScrollRangeChangeListener listener) { - mLauncher.getHotseat().addOnLayoutChangeListener(new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - DeviceProfile dp = mLauncher.getDeviceProfile(); - if (!dp.isVerticalBarLayout()) { - Rect insets = dp.getInsets(); - int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom; - MarginLayoutParams mlp = ((MarginLayoutParams) getLayoutParams()); - int myBot = mlp.topMargin + (int) getTranslationY() + mlp.height; - listener.onScrollRangeChanged(hotseatBottom - myBot); - } else { - listener.onScrollRangeChanged(bottom); - } - } - }); + public void setInsets(Rect insets) { + DeviceProfile dp = mLauncher.getDeviceProfile(); + if (dp.isVerticalBarLayout()) { + mLauncher.getAllAppsController().setScrollRangeDelta(0); + } else { + MarginLayoutParams mlp = ((MarginLayoutParams) getLayoutParams()); + int myBot = mlp.topMargin + (int) getTranslationY() + mlp.height; + mLauncher.getAllAppsController().setScrollRangeDelta( + dp.hotseatBarBottomPaddingPx + myBot); + } } } From a706f00d7873a5bebebc1ae741794dca821e71e7 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 28 Mar 2018 13:55:19 -0700 Subject: [PATCH 20/81] Move default pip position to right above the shelf (Pt. Launcher) SysUI change: ag/3721784, ag/3793664 - Track LauncherState and launcher activity state through callbacks. - Devise logic to send shelf visibility and height signal to SysUI based on LauncherState and Launcher activity state. Bug: 73961893 Test: - By default, pip shows up right above the shelf. - Transitioning to all apps moves the pip down as the shelf becomes invisible. - Going to any specific app moves pip down. Hitting home moves pip right above the shelf again. - Dismissing IME should push PIP down but above the shelf on home screen, bottom if not. Change-Id: I1ab6ceb8007a5a7b5d932a456efa0a07f586ea4c --- .../launcher3/uioverrides/UiFactory.java | 10 ++++++++++ src/com/android/launcher3/BaseActivity.java | 17 +++++++++++++++++ src/com/android/launcher3/Launcher.java | 8 ++++++++ .../android/launcher3/LauncherStateManager.java | 2 ++ .../launcher3/uioverrides/UiFactory.java | 2 ++ 5 files changed, 39 insertions(+) diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 846e80377e..80d63aeb89 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.Utilities.getPrefs; import static com.android.quickstep.OverviewInteractionState.KEY_SWIPE_UP_ENABLED; +import static com.android.launcher3.LauncherState.ALL_APPS; import android.content.Context; import android.content.SharedPreferences; @@ -33,6 +34,7 @@ import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.RecentsModel; import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.system.WindowManagerWrapper; public class UiFactory { @@ -93,6 +95,14 @@ public class UiFactory { } } + public static void onLauncherStateOrResumeChanged(Launcher launcher) { + WindowManagerWrapper.getInstance().setShelfHeight( + launcher.getStateManager().getState() != ALL_APPS && + launcher.isUserActive() && + !launcher.getDeviceProfile().isVerticalBarLayout(), + launcher.getDeviceProfile().hotseatBarSizePx); + } + public static void onTrimMemory(Context context, int level) { RecentsModel model = RecentsModel.getInstance(context); if (model != null) { diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index 02d70c42ca..cf2d79faf2 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -39,6 +39,7 @@ public abstract class BaseActivity extends Activity { protected SystemUiController mSystemUiController; private boolean mStarted; + private boolean mUserActive; public DeviceProfile getDeviceProfile() { return mDeviceProfile; @@ -84,6 +85,18 @@ public abstract class BaseActivity extends Activity { super.onStart(); } + @Override + protected void onResume() { + mUserActive = true; + super.onResume(); + } + + @Override + protected void onUserLeaveHint() { + mUserActive = false; + super.onUserLeaveHint(); + } + @Override protected void onStop() { mStarted = false; @@ -94,6 +107,10 @@ public abstract class BaseActivity extends Activity { return mStarted; } + public boolean isUserActive() { + return mUserActive; + } + public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { mDPChangeListeners.add(listener); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ed94aa4382..985e0968dc 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -379,6 +379,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L } mOldConfig.setTo(newConfig); + UiFactory.onLauncherStateOrResumeChanged(this); super.onConfigurationChanged(newConfig); } @@ -820,6 +821,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L if (mLauncherCallbacks != null) { mLauncherCallbacks.onResume(); } + UiFactory.onLauncherStateOrResumeChanged(this); TraceHelper.endSection("ON_RESUME"); } @@ -838,6 +840,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L } } + @Override + protected void onUserLeaveHint() { + super.onUserLeaveHint(); + UiFactory.onLauncherStateOrResumeChanged(this); + } + @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index 7d50a5263a..ef285df6fa 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -294,6 +294,7 @@ public class LauncherStateManager { // Only disable clipping if needed, otherwise leave it as previous value. mLauncher.getWorkspace().setClipChildren(false); } + UiFactory.onLauncherStateOrResumeChanged(mLauncher); } private void onStateTransitionEnd(LauncherState state) { @@ -312,6 +313,7 @@ public class LauncherStateManager { } UiFactory.onLauncherStateOrFocusChanged(mLauncher); + UiFactory.onLauncherStateOrResumeChanged(mLauncher); } public void onWindowFocusChanged() { diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 94abcce57e..6645e896d2 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -46,6 +46,8 @@ public class UiFactory { public static void onStart(Launcher launcher) { } + public static void onLauncherStateOrResumeChanged(Launcher launcher) { } + public static void onTrimMemory(Launcher launcher, int level) { } public static View[] getHotseatExtraContent(Hotseat hotseat) { From 112c927f8a7503b1d08296548b636f0d0e86a0f9 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 28 Mar 2018 14:41:02 -0700 Subject: [PATCH 21/81] Starting wallpaper picker in a separate task Bug: 74500048 Change-Id: Icb315f3fd3aca800633be5105bf89c6e354425b9 --- .../launcher3/BaseDraggingActivity.java | 2 +- src/com/android/launcher3/Launcher.java | 34 +++---------------- .../launcher3/views/OptionsPopupView.java | 2 +- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 458f7b280f..34819afe43 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -45,7 +45,7 @@ public abstract class BaseDraggingActivity extends BaseActivity { private static final String TAG = "BaseDraggingActivity"; // The Intent extra that defines whether to ignore the launch animation - private static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = + protected static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION"; // When starting an action mode, setting this tag will cause the action mode to be cancelled diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 43a781d4e1..556d25c338 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -22,7 +22,6 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import android.animation.Animator; @@ -147,7 +146,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L private static final int REQUEST_CREATE_APPWIDGET = 5; private static final int REQUEST_PICK_APPWIDGET = 9; - private static final int REQUEST_PICK_WALLPAPER = 10; private static final int REQUEST_BIND_APPWIDGET = 11; public static final int REQUEST_BIND_PENDING_APPWIDGET = 12; @@ -573,14 +571,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L ON_ACTIVITY_RESULT_ANIMATION_DELAY); } return; - } else if (requestCode == REQUEST_PICK_WALLPAPER) { - if (resultCode == RESULT_OK && isInState(OVERVIEW)) { - // User could have free-scrolled between pages before picking a wallpaper; make sure - // we move to the closest one now. - mWorkspace.setCurrentPage(mWorkspace.getPageNearestToCenterOfScreen()); - mStateManager.goToState(NORMAL, false); - } - return; } boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET || @@ -1663,35 +1653,19 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L Toast.makeText(this, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show(); return; } - int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen()); float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll); - setWaitingForResult(new PendingRequestArgs(new ItemInfo())); Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER) .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset); String pickerPackage = getString(R.string.wallpaper_picker_package); - boolean hasTargetPackage = !TextUtils.isEmpty(pickerPackage); - if (hasTargetPackage) { + if (!TextUtils.isEmpty(pickerPackage)) { intent.setPackage(pickerPackage); - } - - final Bundle launchOptions; - if (v != null) { - intent.setSourceBounds(getViewBounds(v)); - // If there is no target package, use the default intent chooser animation - launchOptions = hasTargetPackage - ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat()) - : null; } else { - launchOptions = null; - } - try { - startActivityForResult(intent, REQUEST_PICK_WALLPAPER, launchOptions); - } catch (ActivityNotFoundException e) { - setWaitingForResult(null); - Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + // If there is no target package, use the default intent chooser animation + intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true); } + startActivitySafely(v, intent, null); } @TargetApi(Build.VERSION_CODES.M) diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index dc86aec463..709a7e5c8b 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -107,7 +107,7 @@ public class OptionsPopupView extends AbstractFloatingView private boolean handleViewClick(View view, int action) { if (view.getId() == R.id.wallpaper_button) { - mLauncher.onClickWallpaperPicker(null); + mLauncher.onClickWallpaperPicker(view); logTap(action, ControlType.WALLPAPER_BUTTON); close(true); return true; From 19adf653bde4bcee29df474badd4b6f0745867b8 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 28 Mar 2018 10:19:44 -0700 Subject: [PATCH 22/81] Use onQuickStep call from SysUI Change-Id: I838ef4de2d86abde1848efd757a523c088016756 --- .../android/quickstep/MotionEventQueue.java | 10 ++++ .../quickstep/OtherActivityTouchConsumer.java | 51 +++++++++++-------- .../com/android/quickstep/TouchConsumer.java | 2 + .../quickstep/TouchInteractionService.java | 2 + 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java index 8e6e4c70b8..538e23c3af 100644 --- a/quickstep/src/com/android/quickstep/MotionEventQueue.java +++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java @@ -53,6 +53,8 @@ public class MotionEventQueue { ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT); private static final int ACTION_SHOW_OVERVIEW_FROM_ALT_TAB = ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_QUICK_STEP = + ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT); private final EventArray mEmptyArray = new EventArray(); private final Object mExecutionLock = new Object(); @@ -160,6 +162,9 @@ public class MotionEventQueue { mConsumer.onShowOverviewFromAltTab(); mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB); break; + case ACTION_QUICK_STEP: + mConsumer.onQuickStep(event.getX(), event.getY(), event.getEventTime()); + break; default: Log.e(TAG, "Invalid virtual event: " + event.getAction()); } @@ -204,6 +209,11 @@ public class MotionEventQueue { queueVirtualAction(ACTION_QUICK_SCRUB_END, 0); } + public void onQuickStep(MotionEvent event) { + event.setAction(ACTION_QUICK_STEP); + queueNoPreProcess(event); + } + public void reset() { queueVirtualAction(ACTION_RESET, 0); } diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 4877abbe19..bcc986d5e6 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -79,7 +79,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); private int mActivePointerId = INVALID_POINTER_ID; - private boolean mTouchThresholdCrossed; + private boolean mGestureStarted; private int mTouchSlop; private float mStartDisplacement; private WindowTransformSwipeHandler mInteractionHandler; @@ -122,7 +122,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC mDownPos.set(ev.getX(), ev.getY()); mLastPos.set(mDownPos); mTouchSlop = ViewConfiguration.get(this).getScaledPagingTouchSlop(); - mTouchThresholdCrossed = false; + mGestureStarted = false; // Start the window animation on down to give more time for launcher to draw if the // user didn't start the gesture over the back button @@ -155,26 +155,10 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex)); - float displacement = ev.getY(pointerIndex) - mDownPos.y; - if (isNavBarOnRight()) { - displacement = ev.getX(pointerIndex) - mDownPos.x; - } else if (isNavBarOnLeft()) { - displacement = mDownPos.x - ev.getX(pointerIndex); - } - if (!mTouchThresholdCrossed) { - mTouchThresholdCrossed = Math.abs(displacement) >= mTouchSlop; - if (mTouchThresholdCrossed) { - mStartDisplacement = Math.signum(displacement) * mTouchSlop; - - if (mIsDeferredDownTarget) { - // If we deferred starting the window animation on touch down, then - // start tracking now - startTouchTrackingForWindowAnimation(ev.getEventTime()); - } - notifyGestureStarted(); - } - } else if (mInteractionHandler != null) { + if (mGestureStarted && mInteractionHandler != null) { // Move + float displacement = getDisplacement(ev.getX(pointerIndex), + ev.getY(pointerIndex)); mInteractionHandler.updateDisplacement(displacement - mStartDisplacement); } break; @@ -195,6 +179,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC return; } // Notify the handler that the gesture has actually started + mGestureStarted = true; mInteractionHandler.onGestureStarted(); } @@ -276,7 +261,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC * the animation can still be running. */ private void finishTouchTracking() { - if (mTouchThresholdCrossed && mInteractionHandler != null) { + if (mGestureStarted && mInteractionHandler != null) { mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); @@ -336,6 +321,28 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } } + @Override + public void onQuickStep(float eventX, float eventY, long eventTime) { + float displacement = getDisplacement(eventX, eventY); + mStartDisplacement = Math.signum(displacement) * mTouchSlop; + if (mIsDeferredDownTarget) { + // If we deferred starting the window animation on touch down, then + // start tracking now + startTouchTrackingForWindowAnimation(eventTime); + } + notifyGestureStarted(); + } + + private float getDisplacement(float eventX, float eventY) { + float displacement = eventY - mDownPos.y; + if (isNavBarOnRight()) { + displacement = eventX - mDownPos.x; + } else if (isNavBarOnLeft()) { + displacement = mDownPos.x - eventX; + } + return displacement; + } + public void switchToMainChoreographer() { mEventQueue.setInterimChoreographer(null); } diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java index 4e351595ff..1290ec3375 100644 --- a/quickstep/src/com/android/quickstep/TouchConsumer.java +++ b/quickstep/src/com/android/quickstep/TouchConsumer.java @@ -46,6 +46,8 @@ public interface TouchConsumer extends Consumer { default void onQuickScrubProgress(float progress) { } + default void onQuickStep(float eventX, float eventY, long eventTime) { } + /** * Called on the binder thread to allow the consumer to process the motion event before it is * posted on a handler thread. diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index cc49dc743e..2d58a6b2a3 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -153,6 +153,8 @@ public class TouchInteractionService extends Service { @Override public void onQuickStep(MotionEvent motionEvent) { + mEventQueue.onQuickStep(motionEvent); + TraceHelper.endSection("SysUiBinder", "onQuickStep"); } }; From 7a802eb6dbd00b0858d1ee468ea1a7b71931e1b6 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 29 Mar 2018 09:09:03 -0700 Subject: [PATCH 23/81] Calculate task view animation instead of using dimens Now we compute the precise scales and offsets to synchronize adjacent pages with the launched page. Also adjusted all apps progress so that the predictions/hotseat go offscreen directly based on the opening window. Change-Id: I74e74e541c60b3b116e2b5713522bd4a0f5928a7 --- quickstep/res/values/dimens.xml | 3 - .../LauncherAppTransitionManagerImpl.java | 62 +++++++++++-------- .../RecentsAnimationInterpolator.java | 4 +- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index e354193102..ab6d8af7a4 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -33,9 +33,6 @@ 25dp 80dp - 140dp - 80dp - 150% 16sp 16dp diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 5a090d9e4c..ab4dae8297 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; @@ -55,13 +56,12 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; -import com.android.launcher3.shortcuts.DeepShortcutTextView; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.recents.model.Task; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -104,9 +104,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private final float mContentTransY; private final float mWorkspaceTransY; - private final float mRecentsTransX; - private final float mRecentsTransY; - private final float mRecentsScale; private DeviceProfile mDeviceProfile; private View mFloatingView; @@ -129,9 +126,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Resources res = mLauncher.getResources(); mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y); mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y); - mRecentsTransX = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_x); - mRecentsTransY = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_y); - mRecentsScale = res.getFraction(R.fraction.recents_adjacent_scale, 1, 1); mLauncher.addOnDeviceProfileChangeListener(this); registerRemoteAnimations(); @@ -296,15 +290,22 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag int centerTaskIndex = recentsView.getCurrentPage(); boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex; boolean isRtl = recentsView.isRtl(); + + RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); + TaskWindowBounds endInterpolation = recentsInterpolator.interpolate(1); + float toScale = endInterpolation.taskScale; + float toTranslationY = endInterpolation.taskY; + float displacementX = v.getWidth() * (toScale - v.getScaleX()); if (launchingCenterTask) { + if (launchedTaskIndex - 1 >= 0) { TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1); ObjectAnimator adjacentTask1ScaleAndTranslate = LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1, new PropertyListBuilder() - .scale(adjacentPage1.getScaleX() * mRecentsScale) - .translationY(mRecentsTransY) - .translationX(isRtl ? mRecentsTransX : -mRecentsTransX) + .scale(adjacentPage1.getScaleX() * toScale) + .translationY(toTranslationY) + .translationX(isRtl ? displacementX : -displacementX) .build()); launcherAnimator.play(adjacentTask1ScaleAndTranslate); } @@ -313,20 +314,19 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag ObjectAnimator adjacentTask2ScaleAndTranslate = LauncherAnimUtils.ofPropertyValuesHolder(adjacentTask2, new PropertyListBuilder() - .scale(adjacentTask2.getScaleX() * mRecentsScale) - .translationY(mRecentsTransY) - .translationX(isRtl ? -mRecentsTransX : mRecentsTransX) + .scale(adjacentTask2.getScaleX() * toScale) + .translationY(toTranslationY) + .translationX(isRtl ? -displacementX : displacementX) .build()); launcherAnimator.play(adjacentTask2ScaleAndTranslate); } } else { // We are launching an adjacent task, so parallax the center and other adjacent task. TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex); - float translationX = mRecentsTransX / 2; ObjectAnimator centerTaskParallaxOffscreen = LauncherAnimUtils.ofPropertyValuesHolder(centerTask, new PropertyListBuilder() - .translationX(isRtl ? -translationX : translationX) + .translationX(isRtl ? -displacementX : displacementX) .build()); launcherAnimator.play(centerTaskParallaxOffscreen); int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); @@ -337,14 +337,22 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag ObjectAnimator otherAdjacentTaskParallaxOffscreen = LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, new PropertyListBuilder() - .translationX(isRtl ? -translationX : translationX) + .translationX(isRtl ? -displacementX : displacementX) + .scale(1) .build()); launcherAnimator.play(otherAdjacentTaskParallaxOffscreen); } } + float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN; + LauncherState state = mLauncher.getStateManager().getState(); + if ((state.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) != 0) { + float maxShiftRange = mDeviceProfile.heightPx; + float currShiftRange = mLauncher.getAllAppsController().getShiftRange(); + allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange; + } Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(), - ALL_APPS_PROGRESS, ALL_APPS_PROGRESS_OFF_SCREEN); + ALL_APPS_PROGRESS, allAppsProgressOffscreen); launcherAnimator.play(allAppsSlideOut); Workspace workspace = mLauncher.getWorkspace(); @@ -364,24 +372,28 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return launcherAnimator; } - /** - * @return Animator that controls the window of the opening targets for the recents launch - * animation. - */ - private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges, - RemoteAnimationTargetCompat[] targets) { + private RecentsAnimationInterpolator getRecentsInterpolator(TaskView v) { Rect taskViewBounds = new Rect(); mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); // TODO: Use the actual target insets instead of the current thumbnail insets in case the // device state has changed - RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator( + return new RecentsAnimationInterpolator( new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), v.getThumbnail().getInsets(), taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0), v.getScaleX(), v.getTranslationX()); + } + + /** + * @return Animator that controls the window of the opening targets for the recents launch + * animation. + */ + private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges, + RemoteAnimationTargetCompat[] targets) { + final RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); Rect crop = new Rect(); Matrix matrix = new Matrix(); diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java index 1f9c7281fe..fdeb0c1705 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java @@ -79,8 +79,8 @@ public class RecentsAnimationInterpolator { Rect finalScaledTaskInsets = new Rect(taskInsets); Utilities.scaleRect(finalScaledTaskInsets, mFinalTaskScale); mTargetTask = new Rect(mInsetWindow); - mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top, - window.left + insets.left - finalScaledTaskInsets.left); + mTargetTask.offsetTo(window.left + insets.left - finalScaledTaskInsets.left, + window.top + insets.top - finalScaledTaskInsets.top); float initialWinScale = 1f / mFinalTaskScale; Rect scaledWindow = new Rect(mInsetWindow); From f94c0099eee4697334651a5b3f0e2993ad046c61 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 29 Mar 2018 10:41:30 -0700 Subject: [PATCH 24/81] Import translations. DO NOT MERGE Change-Id: Icf33460413c168778937af5952ca08fd02f3bdca Auto-generated-cl: translation import --- quickstep/res/values-af/strings.xml | 4 ++++ quickstep/res/values-am/strings.xml | 4 ++++ quickstep/res/values-ar/strings.xml | 4 ++++ quickstep/res/values-az/strings.xml | 4 ++++ quickstep/res/values-b+sr+Latn/strings.xml | 4 ++++ quickstep/res/values-be/strings.xml | 4 ++++ quickstep/res/values-bg/strings.xml | 4 ++++ quickstep/res/values-bn/strings.xml | 4 ++++ quickstep/res/values-bs/strings.xml | 4 ++++ quickstep/res/values-ca/strings.xml | 4 ++++ quickstep/res/values-cs/strings.xml | 4 ++++ quickstep/res/values-da/strings.xml | 4 ++++ quickstep/res/values-de/strings.xml | 4 ++++ quickstep/res/values-el/strings.xml | 4 ++++ quickstep/res/values-en-rAU/strings.xml | 2 ++ quickstep/res/values-en-rGB/strings.xml | 2 ++ quickstep/res/values-en-rIN/strings.xml | 2 ++ quickstep/res/values-es-rUS/strings.xml | 4 ++++ quickstep/res/values-es/strings.xml | 4 ++++ quickstep/res/values-et/strings.xml | 4 ++++ quickstep/res/values-eu/strings.xml | 4 ++++ quickstep/res/values-fa/strings.xml | 4 ++++ quickstep/res/values-fi/strings.xml | 4 ++++ quickstep/res/values-fr-rCA/strings.xml | 4 ++++ quickstep/res/values-fr/strings.xml | 4 ++++ quickstep/res/values-gl/strings.xml | 4 ++++ quickstep/res/values-gu/strings.xml | 4 ++++ quickstep/res/values-hi/strings.xml | 4 ++++ quickstep/res/values-hr/strings.xml | 4 ++++ quickstep/res/values-hu/strings.xml | 4 ++++ quickstep/res/values-hy/strings.xml | 4 ++++ quickstep/res/values-in/strings.xml | 2 ++ quickstep/res/values-is/strings.xml | 4 ++++ quickstep/res/values-it/strings.xml | 4 ++++ quickstep/res/values-iw/strings.xml | 4 ++++ quickstep/res/values-ja/strings.xml | 4 ++++ quickstep/res/values-ka/strings.xml | 4 ++++ quickstep/res/values-kk/strings.xml | 4 ++++ quickstep/res/values-km/strings.xml | 4 ++++ quickstep/res/values-kn/strings.xml | 4 ++++ quickstep/res/values-ko/strings.xml | 4 ++++ quickstep/res/values-ky/strings.xml | 4 ++++ quickstep/res/values-lo/strings.xml | 4 ++++ quickstep/res/values-lt/strings.xml | 4 ++++ quickstep/res/values-lv/strings.xml | 4 ++++ quickstep/res/values-mk/strings.xml | 4 ++++ quickstep/res/values-ml/strings.xml | 4 ++++ quickstep/res/values-mn/strings.xml | 4 ++++ quickstep/res/values-mr/strings.xml | 4 ++++ quickstep/res/values-ms/strings.xml | 4 ++++ quickstep/res/values-my/strings.xml | 4 ++++ quickstep/res/values-nb/strings.xml | 4 ++++ quickstep/res/values-ne/strings.xml | 4 ++++ quickstep/res/values-nl/strings.xml | 4 ++++ quickstep/res/values-pa/strings.xml | 4 ++++ quickstep/res/values-pl/strings.xml | 4 ++++ quickstep/res/values-pt-rPT/strings.xml | 2 ++ quickstep/res/values-pt/strings.xml | 4 ++++ quickstep/res/values-ro/strings.xml | 2 ++ quickstep/res/values-ru/strings.xml | 4 ++++ quickstep/res/values-si/strings.xml | 4 ++++ quickstep/res/values-sk/strings.xml | 4 ++++ quickstep/res/values-sl/strings.xml | 4 ++++ quickstep/res/values-sq/strings.xml | 4 ++++ quickstep/res/values-sr/strings.xml | 4 ++++ quickstep/res/values-sv/strings.xml | 4 ++++ quickstep/res/values-sw/strings.xml | 4 ++++ quickstep/res/values-ta/strings.xml | 4 ++++ quickstep/res/values-te/strings.xml | 4 ++++ quickstep/res/values-th/strings.xml | 4 ++++ quickstep/res/values-tl/strings.xml | 4 ++++ quickstep/res/values-tr/strings.xml | 4 ++++ quickstep/res/values-uk/strings.xml | 4 ++++ quickstep/res/values-ur/strings.xml | 4 ++++ quickstep/res/values-uz/strings.xml | 4 ++++ quickstep/res/values-vi/strings.xml | 4 ++++ quickstep/res/values-zh-rCN/strings.xml | 4 ++++ quickstep/res/values-zh-rHK/strings.xml | 4 ++++ quickstep/res/values-zh-rTW/strings.xml | 4 ++++ quickstep/res/values-zu/strings.xml | 4 ++++ res/values-af/strings.xml | 6 ++---- res/values-am/strings.xml | 18 +++++++++--------- res/values-ar/strings.xml | 18 +++++++++--------- res/values-az/strings.xml | 6 ++---- res/values-b+sr+Latn/strings.xml | 18 +++++++++--------- res/values-be/strings.xml | 18 +++++++++--------- res/values-bg/strings.xml | 6 ++---- res/values-bn/strings.xml | 12 ++++-------- res/values-bs/strings.xml | 18 +++++++++--------- res/values-ca/strings.xml | 8 +++----- res/values-cs/strings.xml | 18 +++++++++--------- res/values-da/strings.xml | 13 +++++++------ res/values-de/strings.xml | 18 +++++++++--------- res/values-el/strings.xml | 6 ++---- res/values-en-rAU/strings.xml | 6 ++---- res/values-en-rGB/strings.xml | 6 ++---- res/values-en-rIN/strings.xml | 6 ++---- res/values-es-rUS/strings.xml | 18 +++++++++--------- res/values-es/strings.xml | 6 ++---- res/values-et/strings.xml | 6 ++---- res/values-eu/strings.xml | 6 ++---- res/values-fa/strings.xml | 18 +++++++++--------- res/values-fi/strings.xml | 6 ++---- res/values-fr-rCA/strings.xml | 18 +++++++++--------- res/values-fr/strings.xml | 18 +++++++++--------- res/values-gl/strings.xml | 8 +++----- res/values-gu/strings.xml | 12 ++++-------- res/values-hi/strings.xml | 18 +++++++++--------- res/values-hr/strings.xml | 18 +++++++++--------- res/values-hu/strings.xml | 6 ++---- res/values-hy/strings.xml | 18 +++++++++--------- res/values-in/strings.xml | 6 ++---- res/values-is/strings.xml | 18 +++++++++--------- res/values-it/strings.xml | 6 ++---- res/values-iw/strings.xml | 18 +++++++++--------- res/values-ja/strings.xml | 6 ++---- res/values-ka/strings.xml | 6 ++---- res/values-kk/strings.xml | 6 ++---- res/values-km/strings.xml | 6 ++---- res/values-kn/strings.xml | 12 ++++-------- res/values-ko/strings.xml | 6 ++---- res/values-ky/strings.xml | 6 ++---- res/values-lo/strings.xml | 6 ++---- res/values-lt/strings.xml | 18 +++++++++--------- res/values-lv/strings.xml | 18 +++++++++--------- res/values-mk/strings.xml | 6 ++---- res/values-ml/strings.xml | 12 ++++-------- res/values-mn/strings.xml | 6 ++---- res/values-mr/strings.xml | 12 ++++-------- res/values-ms/strings.xml | 6 ++---- res/values-my/strings.xml | 6 ++---- res/values-nb/strings.xml | 6 ++---- res/values-ne/strings.xml | 12 ++++-------- res/values-nl/strings.xml | 6 ++---- res/values-pa/strings.xml | 12 ++++-------- res/values-pl/strings.xml | 4 ++++ res/values-pt-rPT/strings.xml | 6 ++---- res/values-pt/strings.xml | 18 +++++++++--------- res/values-ro/strings.xml | 6 ++---- res/values-ru/strings.xml | 18 +++++++++--------- res/values-si/strings.xml | 6 ++---- res/values-sk/strings.xml | 6 ++---- res/values-sl/strings.xml | 6 ++---- res/values-sq/strings.xml | 6 ++---- res/values-sr/strings.xml | 18 +++++++++--------- res/values-sv/strings.xml | 6 ++---- res/values-sw/strings.xml | 6 ++---- res/values-ta/strings.xml | 6 ++---- res/values-te/strings.xml | 12 ++++-------- res/values-th/strings.xml | 6 ++---- res/values-tl/strings.xml | 18 +++++++++--------- res/values-tr/strings.xml | 6 ++---- res/values-uk/strings.xml | 18 +++++++++--------- res/values-ur/strings.xml | 12 ++++-------- res/values-uz/strings.xml | 6 ++---- res/values-vi/strings.xml | 6 ++---- res/values-zh-rCN/strings.xml | 18 +++++++++--------- res/values-zh-rHK/strings.xml | 6 ++---- res/values-zh-rTW/strings.xml | 6 ++---- res/values-zu/strings.xml | 18 +++++++++--------- 160 files changed, 670 insertions(+), 481 deletions(-) diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index b4c735b867..415a33ece7 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -22,4 +22,8 @@ "Verdeelde skerm" "Speld vas" "Swiep van onder af op om programme te wissel" + + + + diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 62d54dbe3e..663d23623c 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -22,4 +22,8 @@ "የተከፈለ ማያ ገጽ" "ሰካ" "መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ" + + + + diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index de210b796f..711d02be4b 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -22,4 +22,8 @@ "تقسيم الشاشة" "تثبيت" "التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات" + + + + diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index 91c5179749..f5c9b93eb9 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -22,4 +22,8 @@ "Bölünmüş ekran" "Sancın" "Tətbiqləri dəyişmək üçün aşağıdan yuxarı doğru sürüşdürün" + + + + diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index a4eb3e89d1..6e3a76da51 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -22,4 +22,8 @@ "Podeljeni ekran" "Zakači" "Prevucite nagore da biste prešli na drugu aplikaciju" + + + + diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml index f798802dc5..b03f4a1d53 100644 --- a/quickstep/res/values-be/strings.xml +++ b/quickstep/res/values-be/strings.xml @@ -22,4 +22,8 @@ "Падзяліць экран" "Замацаваць" "Для пераключэння праграм правядзіце па экране пальцам знізу ўверх" + + + + diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index de88634d6e..5f4387e27b 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -22,4 +22,8 @@ "Разделен екран" "Фиксиране" "Прекарайте пръст нагоре от долната част, за да превключите между приложенията" + + + + diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml index 028a475d98..4c7e79b641 100644 --- a/quickstep/res/values-bn/strings.xml +++ b/quickstep/res/values-bn/strings.xml @@ -22,4 +22,8 @@ "স্ক্রিন স্প্লিট করুন" "পিন করুন" "অ্যাপগুলির মধ্যে সুইচ করতে উপর থেকে নিচের দিকে সোয়াইপ করুন" + + + + diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index 16b72ea365..1b10f6e410 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -22,4 +22,8 @@ "Način rada podijeljenog ekrana" "Zakači" "Prevucite od dolje prema gore za promjenu aplikacije" + + + + diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml index 6d65fd7d5e..dc4aa935cd 100644 --- a/quickstep/res/values-ca/strings.xml +++ b/quickstep/res/values-ca/strings.xml @@ -22,4 +22,8 @@ "Divideix la pantalla" "Fixa" "Llisca cap amunt des de la part inferior per canviar d\'aplicació" + + + + diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index b6894c0e1c..f0283e5f86 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -22,4 +22,8 @@ "Rozdělená obrazovka" "PIN" "Aplikace můžete přepínat přejetím zdola nahoru" + + + + diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml index ff2d25d73e..f69bea50cf 100644 --- a/quickstep/res/values-da/strings.xml +++ b/quickstep/res/values-da/strings.xml @@ -22,4 +22,8 @@ "Delt skærm" "Fastgør" "Stryg opad fra bunden for at skifte apps" + + + + diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml index e5242c7a80..6b9ffbbcc4 100644 --- a/quickstep/res/values-de/strings.xml +++ b/quickstep/res/values-de/strings.xml @@ -22,4 +22,8 @@ "Bildschirm teilen" "Fixieren" "Zum Wechseln zwischen Apps vom unteren Bildschirmrand nach oben wischen" + + + + diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index 9d7023de65..ceffc4ba56 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -22,4 +22,8 @@ "Διαχωρισμός οθόνης" "Καρφίτσωμα" "Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών" + + + + diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml index 694e73a956..0a65f2fef7 100644 --- a/quickstep/res/values-en-rAU/strings.xml +++ b/quickstep/res/values-en-rAU/strings.xml @@ -22,4 +22,6 @@ "Split screen" "Pin" "Swipe up from the bottom to switch apps" + "Overview" + "No recent items" diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index 694e73a956..0a65f2fef7 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -22,4 +22,6 @@ "Split screen" "Pin" "Swipe up from the bottom to switch apps" + "Overview" + "No recent items" diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml index 694e73a956..0a65f2fef7 100644 --- a/quickstep/res/values-en-rIN/strings.xml +++ b/quickstep/res/values-en-rIN/strings.xml @@ -22,4 +22,6 @@ "Split screen" "Pin" "Swipe up from the bottom to switch apps" + "Overview" + "No recent items" diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml index 37a3168126..5cb541b480 100644 --- a/quickstep/res/values-es-rUS/strings.xml +++ b/quickstep/res/values-es-rUS/strings.xml @@ -22,4 +22,8 @@ "Pantalla dividida" "Fijar" "Desliza el dedo hacia arriba para cambiar de app" + + + + diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index 60c87d30ca..1b526fda3d 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -22,4 +22,8 @@ "Dividir pantalla" "Fijar" "Desliza el dedo hacia arriba desde la parte inferior para cambiar de aplicación" + + + + diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml index 33d1cba7e8..5fc1c31d84 100644 --- a/quickstep/res/values-et/strings.xml +++ b/quickstep/res/values-et/strings.xml @@ -22,4 +22,8 @@ "Jagatud ekraan" "Kinnita" "Rakenduste vahetamiseks pühkige alaosast üles" + + + + diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml index d0e86c23e4..ed10439e25 100644 --- a/quickstep/res/values-eu/strings.xml +++ b/quickstep/res/values-eu/strings.xml @@ -22,4 +22,8 @@ "Zatitu pantaila" "Ainguratu" "Aplikazioak aldatzeko, pasatu hatza pantailako behealdetik gora" + + + + diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index 198f33db80..a2be1fcd2b 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -22,4 +22,8 @@ "تقسیم صفحه" "پین" "برای تغییر برنامه‌ها،‌ از پایین تند به بالا بکشید" + + + + diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml index f244586fa6..824d9b8169 100644 --- a/quickstep/res/values-fi/strings.xml +++ b/quickstep/res/values-fi/strings.xml @@ -22,4 +22,8 @@ "Jaettu näyttö" "Kiinnitä" "Vaihda sovellusta pyyhkäisemällä alareunasta ylös." + + + + diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml index d9b2a51fe7..94a09eb294 100644 --- a/quickstep/res/values-fr-rCA/strings.xml +++ b/quickstep/res/values-fr-rCA/strings.xml @@ -22,4 +22,8 @@ "Écran divisé" "Épingler" "Balayez l\'écran du bas vers le haut pour changer d\'application" + + + + diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml index 8c1a5d2a75..1c88e33fd1 100644 --- a/quickstep/res/values-fr/strings.xml +++ b/quickstep/res/values-fr/strings.xml @@ -22,4 +22,8 @@ "Écran partagé" "Épingler" "Balayer l\'écran de bas en haut pour changer d\'application" + + + + diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index d6f26accf2..388f3aadb2 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -22,4 +22,8 @@ "Pantalla dividida" "Fixar" "Pasa o dedo cara arriba desde a parte inferior para cambiar de aplicacións" + + + + diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml index 8c779d60ec..9d3da8c262 100644 --- a/quickstep/res/values-gu/strings.xml +++ b/quickstep/res/values-gu/strings.xml @@ -22,4 +22,8 @@ "સ્ક્રીનને વિભાજિત કરો" "પિન કરો" "ઍપને સ્વિચ કરવા માટે નીચેથી ઉપર સ્વાઇપ કરો" + + + + diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml index 65507a9de2..de1d086492 100644 --- a/quickstep/res/values-hi/strings.xml +++ b/quickstep/res/values-hi/strings.xml @@ -22,4 +22,8 @@ "स्क्रीन को दो हिस्सों में बाँटना (स्प्लिट स्क्रीन)" "पिन करना" "ऐप्लिकेशन स्विच करने के लिए सबसे नीचे से ऊपर की ओर स्वाइप करें" + + + + diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index eaa44167e0..aa9307df68 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -22,4 +22,8 @@ "Podijeljeni zaslon" "Prikvači" "Prijeđite prstom od dna prema gore da biste promijenili aplikaciju" + + + + diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml index b72c760b99..5209dded26 100644 --- a/quickstep/res/values-hu/strings.xml +++ b/quickstep/res/values-hu/strings.xml @@ -22,4 +22,8 @@ "Osztott képernyő" "Rögzítés" "Ha váltani szeretne az alkalmazások között, csúsztassa gyorsan az ujját a képernyő aljától felfelé" + + + + diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml index 632ea3e7b8..fb03f671d8 100644 --- a/quickstep/res/values-hy/strings.xml +++ b/quickstep/res/values-hy/strings.xml @@ -22,4 +22,8 @@ "Տրոհել էկրանը" "Ամրացնել" "Սահեցրեք ներքևից վերև՝ մյուս հավելվածին անցնելու համար" + + + + diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index d731bcec98..603ec5a0e2 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -22,4 +22,6 @@ "Layar terpisah" "Pasang pin" "Geser dari bawah ke atas untuk beralih aplikasi" + "Ringkasan" + "Tidak ada item baru-baru ini" diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml index d4d54d3087..b01a749245 100644 --- a/quickstep/res/values-is/strings.xml +++ b/quickstep/res/values-is/strings.xml @@ -22,4 +22,8 @@ "Skipta skjá" "Festa" "Strjúktu upp til að skipta um forrit" + + + + diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml index 6223ddb87d..b1064d7f4a 100644 --- a/quickstep/res/values-it/strings.xml +++ b/quickstep/res/values-it/strings.xml @@ -22,4 +22,8 @@ "Schermo diviso" "Blocca" "Scorri verso l\'alto dalla parte inferiore per cambiare app" + + + + diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml index 1da258aeaf..ab55dfc3fa 100644 --- a/quickstep/res/values-iw/strings.xml +++ b/quickstep/res/values-iw/strings.xml @@ -22,4 +22,8 @@ "מסך מפוצל" "הצמדה" "יש להחליק כלפי מעלה מהחלק התחתון כדי לעבור בין אפליקציות" + + + + diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index bee863fa5a..a5ed5307f3 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -22,4 +22,8 @@ "分割画面" "固定" "アプリを切り替えるには、下から上にスワイプします" + + + + diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml index 4488cf8b67..e845c88429 100644 --- a/quickstep/res/values-ka/strings.xml +++ b/quickstep/res/values-ka/strings.xml @@ -22,4 +22,8 @@ "ეკრანის გაყოფა" "ჩამაგრება" "აპების გადასართავად გადაფურცლეთ ქვედა კიდედან ზემოთ" + + + + diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml index 8c82ef1839..f816fec609 100644 --- a/quickstep/res/values-kk/strings.xml +++ b/quickstep/res/values-kk/strings.xml @@ -22,4 +22,8 @@ "Экранды бөлу" "Бекіту" "Қолданбалар арасында ауысу үшін төменнен жоғары қарай саусақпен сырғытыңыз" + + + + diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index 64136c9bee..7c5f599552 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -22,4 +22,8 @@ "មុខងារ​បំបែកអេក្រង់" "ដៅ" "អូស​ពី​ក្រោម​ឡើង​លើ ដើម្បី​ប្ដូរ​កម្មវិធី" + + + + diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 7f12deef3b..4c0ac63eb3 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -22,4 +22,8 @@ "ಪರದೆಯನ್ನು ಬೇರ್ಪಡಿಸಿ" "ಪಿನ್ ಮಾಡಿ" "ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ" + + + + diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml index 39fdf33113..b4287705b2 100644 --- a/quickstep/res/values-ko/strings.xml +++ b/quickstep/res/values-ko/strings.xml @@ -22,4 +22,8 @@ "화면 분할" "고정" "아래에서 위로 스와이프하여 앱을 전환합니다." + + + + diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml index 2602b51adf..e04d2ed369 100644 --- a/quickstep/res/values-ky/strings.xml +++ b/quickstep/res/values-ky/strings.xml @@ -22,4 +22,8 @@ "Экранды бөлүү" "Кадап коюу" "Колдонмолорду которуштуруу үчүн экранды төмөндөн жогору карай сүрүңүз" + + + + diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml index 7ba29d2331..2411871d3f 100644 --- a/quickstep/res/values-lo/strings.xml +++ b/quickstep/res/values-lo/strings.xml @@ -22,4 +22,8 @@ "ແບ່ງໜ້າຈໍ" "ປັກໝຸດ" "ປັດຂຶ້ນຈາກລຸ່ມສຸດເພື່ອສະຫຼັບແອັບ" + + + + diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index 2252381fb5..924e4d8bd6 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -22,4 +22,8 @@ "Skaidyti ekraną" "Prisegti" "Perbraukite aukštyn iš apačios, kad perjungtumėte programas" + + + + diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index d5f5e9c98d..86a15b7a7b 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -22,4 +22,8 @@ "Sadalīt ekrānu" "Piespraust" "Lai pārslēgtu lietotnes, velciet augšup no apakšdaļas." + + + + diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index 6458aa085a..633fd4423f 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -22,4 +22,8 @@ "Поделен екран" "Прикачување" "Повлечете нагоре од дното за да ги смените апликациите" + + + + diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 4d2745af4f..3981e805eb 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -22,4 +22,8 @@ "സ്‌ക്രീൻ വിഭജിക്കുക" "പിൻ ചെയ്യുക" "ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക" + + + + diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index 4aec25724a..e4253f60d2 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -22,4 +22,8 @@ "Дэлгэцийг хуваах" "Тогтоох" "Аппыг сэлгэхийн тулд доороос дээш шударна уу" + + + + diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml index 3f85d777ef..5b9a621c46 100644 --- a/quickstep/res/values-mr/strings.xml +++ b/quickstep/res/values-mr/strings.xml @@ -22,4 +22,8 @@ "विभाजित स्क्रीन" "पिन करा" "अ‍ॅप्स स्विच करण्यासाठी तळापासून वर स्वाइप करा" + + + + diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml index 80e942cb4a..a13b7bb981 100644 --- a/quickstep/res/values-ms/strings.xml +++ b/quickstep/res/values-ms/strings.xml @@ -22,4 +22,8 @@ "Skrin pisah" "Semat" "Leret ke atas dari bawah untuk menukar apl" + + + + diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index b6b0300a45..38b78d9ddf 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -22,4 +22,8 @@ "မျက်နှာပြင် ခွဲ၍ပြသခြင်း" "ပင်ထိုးခြင်း" "အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ" + + + + diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml index 4dc144cc40..3547ba4e35 100644 --- a/quickstep/res/values-nb/strings.xml +++ b/quickstep/res/values-nb/strings.xml @@ -22,4 +22,8 @@ "Delt skjerm" "Fest" "Sveip opp fra bunnen for å bytte app" + + + + diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index a171b73df0..45387ce0b3 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -22,4 +22,8 @@ "स्क्रिन विभाजन गर्नुहोस्" "पिन गर्नुहोस्" "अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्" + + + + diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml index 4acddc54b3..a8e092a50e 100644 --- a/quickstep/res/values-nl/strings.xml +++ b/quickstep/res/values-nl/strings.xml @@ -22,4 +22,8 @@ "Gesplitst scherm" "Vastzetten" "Veeg omhoog vanaf de onderkant om tussen apps te wisselen" + + + + diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index 6bc1876b57..38d7499340 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -22,4 +22,8 @@ "ਸਪਲਿਟ ਸਕ੍ਰੀਨ" "ਪਿੰਨ ਕਰੋ" "ਐਪਾਂ ਵਿੱਚ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ" + + + + diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml index 174a96a767..5a730ac1db 100644 --- a/quickstep/res/values-pl/strings.xml +++ b/quickstep/res/values-pl/strings.xml @@ -22,4 +22,8 @@ "Podziel ekran" "Przypnij" "Przesuń palcem z dołu ekranu, by przełączać aplikacje" + + + + diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml index c3df4f2438..f2496a02ac 100644 --- a/quickstep/res/values-pt-rPT/strings.xml +++ b/quickstep/res/values-pt-rPT/strings.xml @@ -22,4 +22,6 @@ "Ecrã dividido" "Fixar" "Deslize rapidamente para cima a partir da parte inferior para alternar entre aplicações." + "Vista geral" + "Nenhum item recente" diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index 9730b98c30..5c71fdb356 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -22,4 +22,8 @@ "Tela dividida" "Fixar" "Deslize de baixo para cima para alternar entre apps" + + + + diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml index 46671e8350..c4d2338081 100644 --- a/quickstep/res/values-ro/strings.xml +++ b/quickstep/res/values-ro/strings.xml @@ -22,4 +22,6 @@ "Ecran divizat" "Fixați" "Glisați de jos în sus pentru a schimba aplicațiile" + "Recente" + "Niciun element recent" diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index c2edf750b7..922f940334 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -22,4 +22,8 @@ "Разделить экран" "Блокировать" "Чтобы переключить приложение, проведите по экрану снизу вверх" + + + + diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index 7702543ecc..8c3c4a64e5 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -22,4 +22,8 @@ "බෙදුම් තිරය" "අමුණන්න" "යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න" + + + + diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index 84e779324d..1faccf8702 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -22,4 +22,8 @@ "Rozdeliť obrazovku" "Pripnúť" "Aplikácie môžete prepínať potiahnutím prstom zdola nahor" + + + + diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index c01fcd42a8..19ad7eb5c4 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -22,4 +22,8 @@ "Razdeljen zaslon" "Pripni" "Če želite preklopiti med aplikacijami, z dna zaslona s prstom povlecite navzgor" + + + + diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index ae6e6bc961..cec4668364 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -22,4 +22,8 @@ "Ekrani i ndarë" "Gozhdo" "Rrëshqit larg nga poshtë për të ndryshuar aplikacionet" + + + + diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index 84debfd670..9c031e9bce 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -22,4 +22,8 @@ "Подељени екран" "Закачи" "Превуците нагоре да бисте прешли на другу апликацију" + + + + diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml index 495bca7960..e7bdf190b2 100644 --- a/quickstep/res/values-sv/strings.xml +++ b/quickstep/res/values-sv/strings.xml @@ -22,4 +22,8 @@ "Delad skärm" "Fäst" "Växla mellan appar genom att svepa uppåt från nederkanten" + + + + diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index 63594f2bf7..dc1ad83360 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -22,4 +22,8 @@ "Gawa skrini" "Bandika" "Telezesha kidole juu kuanzia chini ili ubadilishe programu" + + + + diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml index 2d740cab9b..de03ae62e8 100644 --- a/quickstep/res/values-ta/strings.xml +++ b/quickstep/res/values-ta/strings.xml @@ -22,4 +22,8 @@ "திரைப் பிரிப்பு" "பின் செய்தல்" "ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்க" + + + + diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 36e5e3ef70..9c353af6a2 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -22,4 +22,8 @@ "స్క్రీన్‌ని విభజించు" "పిన్ చేయి" "యాప్‌లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి" + + + + diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 882b096122..4e88146c00 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -22,4 +22,8 @@ "แยกหน้าจอ" "ตรึง" "เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป" + + + + diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index dbd03b162c..5540f089ce 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -22,4 +22,8 @@ "Hatiin ang screen" "I-pin" "Mag-swipe pataas mula sa ibaba para lumipat ng app" + + + + diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index 57cb3499e3..dc5c45fb8e 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -22,4 +22,8 @@ "Bölünmüş ekran" "Sabitle" "Uygulamaları değiştirmek için alttan yukarı kaydırın" + + + + diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 8c2c6f6f0b..21f7c746e0 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -22,4 +22,8 @@ "Розділити екран" "Закріпити" "Щоб переходити між додатками, проводьте пальцем знизу вгору" + + + + diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml index ab5b38f756..341ab0d5c3 100644 --- a/quickstep/res/values-ur/strings.xml +++ b/quickstep/res/values-ur/strings.xml @@ -22,4 +22,8 @@ "اسپلٹ اسکرین وضع" "پن کریں" "ایپس کو سوئچ کرنے کیلئے نیچے سے اوپر سوائپ کریں" + + + + diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml index 280bd88df2..bb6edb77c4 100644 --- a/quickstep/res/values-uz/strings.xml +++ b/quickstep/res/values-uz/strings.xml @@ -22,4 +22,8 @@ "Ekranni ikkiga ajratish" "Mahkamlash" "Ilovalarni almashtirish uchun pastdan yuqoriga suring" + + + + diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 2aca3b8076..2241f022af 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -22,4 +22,8 @@ "Chia đôi màn hình" "Ghim" "Vuốt từ dưới lên để chuyển đổi ứng dụng" + + + + diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml index 165f141331..77b6432b40 100644 --- a/quickstep/res/values-zh-rCN/strings.xml +++ b/quickstep/res/values-zh-rCN/strings.xml @@ -22,4 +22,8 @@ "分屏" "固定" "从屏幕底部向上滑动即可切换应用" + + + + diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index 6ba0244c6a..1443cba45d 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -22,4 +22,8 @@ "分割畫面" "固定" "從螢幕底部向上快速滑動,即可切換應用程式" + + + + diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index 9834038218..c93c537991 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -22,4 +22,8 @@ "分割畫面" "固定" "從畫面底部向上滑動以切換應用程式" + + + + diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index a4ba48ca4d..56172b4f4b 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -22,4 +22,8 @@ "Hlukanisa isikrini" "Phina" "Swayiphela phezulu kusukela phansi ukuze ushintshe izinhlelo zokusebenza" + + + + diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index d24b63cea4..02dd1c98a4 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -40,10 +40,8 @@ "Kon geen programme kry wat by \"%1$s\" pas nie" "Soek meer programme" "Kennisgewings" - - - - + "Raak en hou om \'n kortpad op te tel." + "Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge." "Niks meer spasie op die tuisskerm nie." "Geen plek meer in die Gunstelinge-laai nie" "Programmelys" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 07fe5ef7b1..21b01ddb09 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -40,9 +40,13 @@ "ከ«%1$s» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም" "ተጨማሪ መተግበሪያዎች ይፈልጉ" "ማሳወቂያዎች" + "አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ።" + "አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።" "በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።" "በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም" "የመተግበሪያዎች ዝርዝር" + "የግል መተግበሪያዎች ዝርዝር" + "የሥራ መተግበሪያዎች ዝርዝር" "መነሻ" "አስወግድ" "አራግፍ" @@ -77,19 +81,17 @@ "የግድግዳ ወረቀቶች" "የመነሻ ቅንብሮች" "በእርስዎ አስተዳዳሪ የተሰናከለ" - "አጠቃላይ ዕይታ" - "የመነሻ ማያ ገጽ ማሽከርከርን ይፍቀዱ" - "ስልኩ ሲዞር" - "የአሁኑ የማሳያ ቅንብር ማሽከርከርን አይፈቅድም" "የማሳወቂያ ነጥቦች" "በርቷል" "ጠፍቷል" "የማሳወቂያ መዳረሻ ያስፈልጋል" "የማሳወቂያ ነጥቦችን ለማሳየት የመተግብሪያ ማሳወቂያዎችን ለ%1$s ያብሩ" "ቅንብሮችን ቀይር" + "የማሳወቂያ ነጥቦችን አሳይ" "አዶ ወደ የመነሻ ማያ ገጽ አክል" "ለአዲስ መተግበሪያዎች" "የአዶ ቅርፅ ለውጥ" + "በመነሻ ማያ ገጽ ላይ" "የሥርዓቱን ነባሪ ተጠቀም" "ካሬ" "Squircle" @@ -119,9 +121,6 @@ "አቃፊ ፍጠር ከዚህ ጋር፦ %1$s" "አቃፊ ተፈጥሮዋል" "ወደ መነሻ ማያ ገጽ አንቀሳቅስ" - "ማያ ገጽን ወደ ግራ አንቀሳቅስ" - "ማያ ገጽን ወደ ቀኝ አንቀሳቅስ" - "ማያ ገጽ ተንቀሳቅሷል" "መጠን ቀይር" "ስፋት ጨምር" "ቁመት ጨምር" @@ -137,8 +136,9 @@ "ሥራ" "የሥራ መገለጫ" "የስራ መተግበሪያዎችን እዚህ ያግኙ" - - + "እያንዳንዱ የሥራ መተግበሪያ ባጅ አለው፣ እና በድርጅትዎ ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ይውሰዷቸው።" "በእርስዎ ድርጅት የሚተዳደር" "ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል" + "ዝጋ" + "ዝግ" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 95508e1212..8598a8bb85 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -40,9 +40,13 @@ "لم يتم العثور على أي تطبيقات تتطابق مع \"%1$s\"" "البحث عن مزيد من التطبيقات" "الإشعارات" + "انقر مع الاستمرار لاختيار اختصار." + "يمكنك النقر نقرًا مزدوجًا مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة." "ليس هناك مساحة أخرى في هذه الشاشة الرئيسية." "لا يوجد المزيد من الحقول في علبة المفضلة" "قائمة التطبيقات" + "قائمة التطبيقات الشخصية" + "قائمة تطبيقات العمل" "الرئيسية" "إزالة" "إلغاء التثبيت" @@ -81,19 +85,17 @@ "الخلفيات" "إعدادات الصفحة الرئيسية" "عطَّل المشرف هذه الميزة" - "نظرة عامة" - "السماح بتدوير الشاشة الرئيسية" - "عند تدوير الهاتف" - "لا يسمح إعداد العرض الحالي بالتدوير" "نقاط الإشعارات" "قيد التشغيل" "قيد الإيقاف" "يلزم تمكين الوصول إلى الإشعارات" "لعرض نقاط الإشعارات، يجب تشغيل إشعارات التطبيق في %1$s" "تغيير الإعدادات" + "عرض نقاط الإشعارات" "إضافة رمز إلى الشاشة الرئيسية" "للتطبيقات الجديدة" "تغيير شكل الرمز" + "على الشاشة الرئيسية" "استخدام الإعداد الافتراضي للنظام" "مربّع" "رمز دائري مربّع" @@ -123,9 +125,6 @@ "إنشاء مجلد يتضمن: %1$s" "تم إنشاء المجلد" "نقل إلى الشاشة الرئيسية" - "نقل الشاشة إلى اليسار" - "نقل الشاشة إلى اليمين" - "تم نقل الشاشة" "تغيير حجم" "زيادة العرض" "زيادة الارتفاع" @@ -141,8 +140,9 @@ "للعمل" "الملف الشخصي للعمل" "البحث عن تطبيقات العمل هنا" - - + "يحتوي كل تطبيق للعمل على شارة ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول إليها." "ملف شخصي للعمل تديره مؤسستك" "الإشعارات والتطبيقات متوقفة." + "إغلاق" + "تمّ الإغلاق" diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index b4b3c79174..a0a1f57731 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -40,10 +40,8 @@ "%1$s sorğusuna uyğun tətbiq tapılmadı" "Daha çox tətbiq üçün axtarış edin" "Bildirişlər" - - - - + "Qısayolu seçmək üçün basıb saxlayın." + "Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin." "Bu Əsas ekranda boş yer yoxdur." "Favoritlər-də yer yoxdur" "Tətbiq siyahısı" diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index 4b577bad19..275cf0f250 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -40,9 +40,13 @@ "Nije pronađena nijedna aplikacija za „%1$s“" "Pretraži još aplikacija" "Obaveštenja" + "Dodirnite i zadržite da biste izabrali prečicu." + "Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje." "Nema više prostora na ovom početnom ekranu." "Nema više prostora na traci Omiljeno" "Lista aplikacija" + "Lista ličnih aplikacija" + "Lista poslovnih aplikacija" "Početna" "Ukloni" "Deinstaliraj" @@ -78,19 +82,17 @@ "Pozadine" "Podešavanja početnog ekrana" "Administrator je onemogućio" - "Pregled" - "Dozvoli rotaciju početnog ekrana" - "Kada se telefon rotira" - "Aktuelno podešavanje prikaza ne dozvoljava rotaciju" "Tačke za obaveštenja" "Uključeno" "Isključeno" "Potreban je pristup za obaveštenja" "Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju %1$s" "Promenite podešavanja" + "Prikazuj tačke za obaveštenja" "Dodaj ikonu na početni ekran" "Za nove aplikacije" "Promenite oblik ikona" + "na početnom ekranu" "Koristi podrazumevano sistemsko podešavanje" "Kvadrat" "Zaobljeni kvadrat" @@ -120,9 +122,6 @@ "Napravite direktorijum sa: %1$s" "Direktorijum je napravljen" "Premesti na početni ekran" - "Pomeri ekran ulevo" - "Pomeri ekran udesno" - "Ekran je pomeren" "Promeni veličinu" "Povećaj širinu" "Povećaj visinu" @@ -138,8 +137,9 @@ "Poslovne" "Profil za Work" "Pronađite poslovne aplikacije ovde" - - + "Svaka poslovna aplikacija ima značku i štiti je vaša organizacija. Premestite aplikacije na početni ekran da biste im lakše pristupali." "Ovim upravlja organizacija" "Obaveštenja i aplikacije su isključeni" + "Zatvori" + "Zatvoreno" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 155ac3cdfe..a1f1d8912a 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -40,9 +40,13 @@ "Праграм, якія адпавядаюць запыту \"%1$s\", не знойдзена" "Шукаць іншыя праграмы" "Апавяшчэнні" + "Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго." + "Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні." "На гэтым Галоўным экране больш няма месца." "У латку \"Абранае\" больш няма месца" "Спіс праграм" + "Спіс персанальных праграм" + "Спіс працоўных праграм" "Галоўная" "Выдаліць" "Выдаліць" @@ -79,19 +83,17 @@ "Шпалеры" "Налады галоўнага экрана" "Адключаная адміністратарам" - "Агляд" - "Дазволіць паварот галоўнага экрана" - "Пры павароце тэлефона" - "Бягучая налада дысплэя не прадугледжвае паварот" "Значкі апавяшчэнняў" "Уключана" "Выключана" "Патрабуецца доступ да апавяшчэнняў" "Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для %1$s" "Змяніць налады" + "Паказаць значкі апавяшчэнняў" "Дадаць значок на Галоўны экран" "Для новых праграм" "Змяніць форму значка" + "на галоўным экране" "Выкарыстоўваць стандартныя формы" "Квадрат" "Прамавугольнік са скругленымі вугламі" @@ -121,9 +123,6 @@ "Стварыць папку з: %1$s" "Папка створана" "Перамясціць на Галоўны экран" - "Перамясціць экран налева" - "Перамясціць экран направа" - "Экран перамешчаны" "Змяніць памер" "Павялічыць шырыню" "Павялічыць вышыню" @@ -139,8 +138,9 @@ "Праца" "Працоўны профіль" "Знайдзіце працоўныя праграмы тут" - - + "Кожная працоўная праграма мае значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на Галоўны экран." "Пад кіраваннем вашай арганізацыі" "Апавяшчэнні і праграмы выключаны" + "Закрыць" + "Закрытыя" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index e664570527..3c04905775 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -40,10 +40,8 @@ "Няма намерени приложения, съответстващи на „%1$s“" "Търсене на още приложения" "Известия" - - - - + "Докоснете и задръжте за избор на пряк път." + "Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия." "На този начален екран няма повече място." "Няма повече място в областта с любимите" "Списък с приложения" diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 46a9a39026..a0e4812cc3 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি" "আরও অ্যাপ্লিকেশানের জন্য খুঁজুন" "বিজ্ঞপ্তি" - - - - + "কোনও শর্টকাট বেছে নিতে টাচ করে ধরে থাকুন।" + "কোনও শর্টকাট বেছে নিতে ডবল ট্যাপ করে ধরে থাকুন অথবা কাস্টম অ্যাকশন ব্যবহার করুন।" "এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷" "পছন্দসই ট্রে-তে আর কোনো জায়গা নেই" "অ্যাপ্লিকেশানগুলির তালিকা" @@ -141,8 +139,6 @@ "প্রতিটি কাজের অ্যাপে একটি করে ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।" "আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত" "বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে" - - - - + "বন্ধ করুন" + "বন্ধ" diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index a96abdee8e..08a453360d 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -40,9 +40,13 @@ "Nije pronađena nijedna aplikacija za upit \"%1$s\"" "Pretraži više aplikacija" "Obavještenja" + "Dodirnite i držite da uzmete prečicu." + "Dvaput dodirnite i držite da uzmete prečicu ili koristite prilagođene akcije." "Na ovom početnom ekranu nema više prostora." "Nema više prostora u ladici Omiljeno" "Spisak aplikacija" + "Lista ličnih aplikacija" + "Lista poslovnih aplikacija" "Početna" "Ukloni" "Deinstaliraj" @@ -78,19 +82,17 @@ "Pozadinske slike" "Postavke za Home" "Onemogućio vaš administrator" - "Pregled" - "Dozvoli rotiranje početnog ekrana" - "Kada se telefon zarotira" - "Trenutne postavke ekrana ne dozvoljavaju rotiranje" "Tačke za obavještenja" "Uključeno" "Isključeno" "Potreban je pristup obavještenjima" "Za prikaz tačaka obavještenja, uključite obavještenja za aplikacije za aplikaciju %1$s" "Promijeni postavke" + "Prikaži tačke za obavještenja" "Dodaj ikonu na početni ekran" "Za nove aplikacije" "Promjena oblika ikona" + "na Početnom ekranu" "Koristite sistemski zadano" "Kvadrat" "Zaobljeni kvadrat" @@ -120,9 +122,6 @@ "Kreirajte folder sa stavkom: %1$s" "Folder je kreiran" "Pomjeri na početni ekran" - "Pomjeri ekran ulijevo" - "Pomjeri ekran udesno" - "Ekran je pomjeren" "Promijeni veličinu" "Povećaj širinu" "Povećaj visinu" @@ -138,8 +137,9 @@ "Poslovne" "Radni profil" "Pronađite poslovne aplikacije ovdje" - - + "Svaka poslovna aplikacija ima značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa." "Upravlja vaša organizacija" "Notifikacije i aplikacije su isključene" + "Zatvori" + "Zatvoreno" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 57736296ba..27b2979e15 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -40,10 +40,8 @@ "No s\'ha trobat cap aplicació que coincideixi amb \"%1$s\"" "Cerca més aplicacions" "Notificacions" - - - - + "Mantén premuda una drecera per seleccionar-la." + "Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades." "Ja no queda espai en aquesta pantalla d\'inici." "No hi ha més espai a la safata Preferits." "Llista d\'aplicacions" @@ -142,5 +140,5 @@ "Gestionat per la teva organització" "Les notificacions i les aplicacions estan desactivades" "Tanca" - "Tancada" + "S\'ha tancat" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 608d297ff5..eee945c209 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -40,9 +40,13 @@ "Dotazu „%1$s“ neodpovídají žádné aplikace" "Vyhledat další aplikace" "Oznámení" + "Zkratku vyberete podržením." + "Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce." "Na této ploše již není místo." "Na panelu Oblíbené položky již není místo." "Seznam aplikací" + "Seznam osobních aplikací" + "Seznam pracovních aplikací" "Plocha" "Odstranit" "Odinstalovat" @@ -79,19 +83,17 @@ "Tapety" "Nastavení plochy" "Zakázáno administrátorem" - "Přehled" - "Povolit otáčení plochy" - "Při otočení telefonu" - "Aktuální nastavení displeje neumožňuje otáčení" "Puntíky s oznámením" "Zapnuto" "Vypnuto" "Je třeba udělit přístup k oznámením" "Chcete-li zobrazovat puntíky s oznámením, zapněte oznámení z aplikace %1$s" "Změnit nastavení" + "Zobrazovat puntíky s oznámením" "Přidat ikonu na plochu" "Pro nové aplikace" "Změnit tvar ikony" + "na ploše" "Použít výchozí nastavení systému" "Čtverec" "Kruh/čtverec" @@ -121,9 +123,6 @@ "Vytvořit složku s položkou %1$s" "Složka byla vytvořena" "Přesunout na plochu" - "Přesunout obrazovku doleva" - "Přesunout obrazovku doprava" - "Obrazovka byla přesunuta" "Změnit velikost" "Zvýšit šířku" "Zvýšit výšku" @@ -139,8 +138,9 @@ "Pracovní" "Pracovní profil" "Zde naleznete pracovní aplikace" - - + "Každá pracovní aplikace má odznak a je zabezpečena vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu." "Spravováno vaší organizací" "Oznámení a aplikace jsou vypnuty" + "Zavřít" + "Zavřeno" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 79fa9f12d2..203a9da7d4 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -40,13 +40,13 @@ "Der blev ikke fundet nogen apps, som matcher \"%1$s\"" "Søg efter flere apps" "Underretninger" + "Hold en genvej nede for at samle den op." + "Tryk to gange, og hold en genvej nede for at samle den op eller bruge tilpassede handlinger." "Der er ikke mere plads på denne startskærm." "Der er ikke mere plads i bakken Foretrukne" "Liste med apps" - - - - + "Liste over personlige apps" + "Liste over apps til arbejdet" "Startskærm" "Fjern" "Afinstaller" @@ -91,8 +91,7 @@ "Føj ikon til startskærmen" "For nye apps" "Skift ikonform" - - + "på startskærmen" "Brug systemstandarden" "Kvadrat" "Kvadrat med runde hjørner" @@ -140,4 +139,6 @@ "Alle arbejdsapps har et badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem." "Administreret af din organisation" "Underretninger og apps er slået fra" + "Luk" + "Lukket" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 5cc1451b3b..f012a9ee63 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -40,9 +40,13 @@ "Keine Apps für \"%1$s\" gefunden" "Weitere Apps suchen" "Benachrichtigungen" + "Tippen und halten, um eine Verknüpfung auszuwählen." + "Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen." "Auf diesem Startbildschirm ist kein Platz mehr vorhanden." "Ablage \"Favoriten\" ist voll." "Liste der Apps" + "Liste der privaten Apps" + "Liste der geschäftlichen Apps" "Startseite" "Entfernen" "Deinstallieren" @@ -77,19 +81,17 @@ "Hintergründe" "Einstellungen für den Startbildschirm" "Von deinem Administrator deaktiviert" - "Übersicht" - "Drehung des Startbildschirms zulassen" - "Bei Drehung des Smartphones" - "Die aktuelle \"Display\"-Einstellung verhindert eine Drehung der Anzeige" "App-Benachrichtigungspunkte" "Aktiviert" "Deaktiviert" "Benachrichtigungszugriff erforderlich" "Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"%1$s\"" "Einstellungen ändern" + "App-Benachrichtigungspunkte anzeigen" "Symbol zu Startbildschirm hinzufügen" "Für neue Apps" "Form des Symbols ändern" + "auf dem Startbildschirm" "Systemstandardeinstellung verwenden" "Quadrat" "Superkreis" @@ -119,9 +121,6 @@ "Anhand von %1$s Ordner erstellen" "Ordner erstellt" "Auf Startbildschirm verschieben" - "Bildschirm nach links" - "Bildschirm nach rechts" - "Bildschirm verschoben" "Größe anpassen" "Breite vergrößern" "Höhe vergrößern" @@ -137,8 +136,9 @@ "Geschäftlich" "Arbeitsprofil" "Hier findest du Apps für die Arbeit" - - + "Jede App für die Arbeit ist mit einem Logo gekennzeichnet. Deine Organisation kümmert sich um den entsprechenden Schutz. Damit du leichter auf Apps zugreifen kannst, verschiebe sie auf deinen Startbildschirm." "Wird von deiner Organisation verwaltet" "Benachrichtigungen und Apps sind deaktiviert" + "Schließen" + "Geschlossen" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index e139e44064..18eec841fa 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -40,10 +40,8 @@ "Δεν βρέθηκαν εφαρμογές αντιστοίχισης για \"%1$s\"" "Αναζήτηση περισσότερων εφαρμογών" "Ειδοποιήσεις" - - - - + "Αγγίξτε παρατεταμένα για επιλογή συντόμευσης." + "Πατήσετε δύο φορές παρατεταμένα για επιλογή συντόμευσης ή χρήση προσαρμοσμένων ενεργειών." "Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη." "Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα" "Λίστα εφαρμογών" diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 5b1e39adf7..c2e37b8e51 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -40,10 +40,8 @@ "No apps found matching \'%1$s\'" "Search for more apps" "Notifications" - - - - + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." "No more room on this Home screen." "No more room in the Favourites tray" "Apps list" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 5b1e39adf7..c2e37b8e51 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -40,10 +40,8 @@ "No apps found matching \'%1$s\'" "Search for more apps" "Notifications" - - - - + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." "No more room on this Home screen." "No more room in the Favourites tray" "Apps list" diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 5b1e39adf7..c2e37b8e51 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -40,10 +40,8 @@ "No apps found matching \'%1$s\'" "Search for more apps" "Notifications" - - - - + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." "No more room on this Home screen." "No more room in the Favourites tray" "Apps list" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 23bf97d5e9..989cd619e7 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -40,9 +40,13 @@ "No hay apps que coincidan con \"%1$s\"" "Buscar más apps" "Notificaciones" + "Mantén presionado para elegir un acceso directo." + "Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas." "No hay más espacio en esta pantalla principal." "La bandeja de favoritos está llena." "Lista de apps" + "Lista de apps personales" + "Lista de apps del trabajo" "Pantalla principal" "Quitar" "Desinstalar" @@ -77,19 +81,17 @@ "Fondos de pantalla" "Configuración de Home" "El administrador inhabilitó esta función" - "Recientes" - "Permitir la rotación de la pantalla principal" - "Al girar el teléfono" - "La configuración actual no permite la rotación de la pantalla" "Puntos de notificación" "Activada" "Desactivada" "Se necesita acceso a las notificaciones" "Para mostrar los puntos de notificación, activa las notificaciones de la app para %1$s" "Cambiar la configuración" + "Mostrar puntos de notificación" "Agregar ícono a la pantalla principal" "Para nuevas apps" "Cambiar forma de los íconos" + "en la pantalla principal" "Usar el sistema predeterminado" "Cuadrado" "Cuadrado con esquinas redondeadas" @@ -119,9 +121,6 @@ "Crear carpeta con: %1$s" "Carpeta creada" "Mover a la pantalla principal" - "Mover pantalla a la izquierda" - "Mover pantalla a la derecha" - "Se movió la pantalla." "Ajustar tamaño" "Aumentar el ancho" "Aumentar la altura" @@ -137,8 +136,9 @@ "Laborales" "Perfil de trabajo" "Apps de trabajo" - - + "Cada app de trabajo tiene una insignia y está protegida por tu organización. Transfiere las apps a la pantalla principal para acceder a ellas con mayor facilidad." "Administrado por tu organización" "Las notificaciones y las apps están desactivadas" + "Cerrar" + "Cerrado" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index f6337fcb2c..877d1501d6 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -40,10 +40,8 @@ "No se han encontrado aplicaciones que contengan \"%1$s\"" "Buscar más aplicaciones" "Notificaciones" - - - - + "Mantén pulsado el acceso directo que quieras." + "Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas." "No queda espacio en la pantalla de inicio." "La bandeja de favoritos está completa" "Lista de aplicaciones" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index fb24c2ab0d..2946076f5d 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -40,10 +40,8 @@ "Päringule „%1$s” ei vastanud ükski rakendus" "Otsi rohkem rakendusi" "Märguanded" - - - - + "Otsetee valimiseks puudutage seda pikalt." + "Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks." "Sellel avaekraanil pole enam ruumi." "Salves Lemmikud pole rohkem ruumi" "Rakenduste loend" diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 45aa3f77cd..c3099bd98e 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -40,10 +40,8 @@ "Ez da aurkitu \"%1$s\" bilaketaren emaitzarik" "Bilatu aplikazio gehiago" "Jakinarazpenak" - - - - + "Eduki sakatuta lasterbide bat aukeratzeko." + "Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko." "Hasierako pantaila honetan ez dago toki gehiago." "Ez dago toki gehiago Gogokoak erretiluan" "Aplikazioen zerrenda" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 5528119723..4843d6d9e4 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -40,9 +40,13 @@ "هیچ برنامه‌ای در مطابقت با «%1$s» پیدا نشد" "جستجوی برنامه‌های بیشتر" "اعلان‌ها" + "برای انتخاب میان‌بر، لمس کنید و نگه‌دارید." + "برای انتخاب میان‌بر، دو ضربه سریع بزنید و نگه‌دارید یا از کنش‌های سفارشی استفاده کنید." "فضای بیشتری در این صفحه اصلی موجود نیست." "فضای بیشتری در سینی موارد دلخواه وجود ندارد" "فهرست برنامه‌ها" + "فهرست برنامه‌های شخصی" + "فهرست برنامه‌های کاری" "صفحه اصلی" "برداشتن" "حذف نصب" @@ -77,19 +81,17 @@ "کاغذدیواری‌ها" "تنظیمات صفحه اصلی" "توسط سرپرست سیستم غیرفعال شده است" - "نمای کلی" - "امکان دادن به چرخش صفحه اصلی" - "وقتی تلفن چرخانده می‌شود" - "تنظیم نمایشگر کنونی اجازه چرخش نمی‌دهد" "نقطه‌های اعلان" "روشن" "خاموش" "دسترسی به اعلان نیاز است" "برای نمایش «نقطه‌های اعلان»، اعلان‌های برنامه را برای %1$s روشن کنید" "تغییر تنظیمات" + "نمایش نقطه‌های اعلان" "افزودن نماد به صفحه اصلی" "برای برنامه‌های جدید" "تغییر شکل نماد" + "در صفحه اصلی" "استفاده از پیش‌فرض سیستم" "مربع" "مربع با گوشه‌های گرد" @@ -119,9 +121,6 @@ "ایجاد پوشه با: %1$s" "پوشه ایجاد شد" "انتقال به صفحه اصلی" - "انتقال صفحه به چپ" - "انتقال صفحه به راست" - "صفحه منتقل شد" "تغییر اندازه" "افزایش عرض" "افزایش ارتفاع" @@ -137,8 +136,9 @@ "محل کار" "نمایه کاری" "اینجا برنامه‌های کاری را پیدا کنید" - - + "همه برنامه‌های کاری نشانی دارند و توسط سازمانتان ایمن نگه داشته می‌شوند. برنامه‌های کاری را برای دسترسی آسان‌تر به صفحه اصلی انتقال دهید." "توسط سازمانتان مدیریت می‌شود" "اعلان‌ها و برنامه‌ها خاموش هستند" + "بستن" + "بسته‌شده" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 0a7d455846..5ffc414558 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -40,10 +40,8 @@ "%1$s ei palauttanut sovelluksia." "Hae lisää sovelluksia" "Ilmoitukset" - - - - + "Valitse pikakuvake painamalla sitä pitkään." + "Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään." "Tässä aloitusruudussa ei ole enää tilaa." "Suosikit-valikossa ei ole enää tilaa" "Sovellusluettelo" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index c6961805fd..d6903efb1a 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -40,9 +40,13 @@ "Aucune application trouvée correspondant à « %1$s »" "Rechercher plus d\'applications" "Notifications" + "Maintenez un doigt sur le raccourci pour l\'ajouter" + "Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées." "Pas d\'espace libre sur l\'écran d\'accueil." "Il n\'y a plus d\'espace dans la zone des favoris" "Liste des applications" + "Liste des applications personnelles" + "Liste des applications professionnelles" "Accueil" "Supprimer" "Désinstaller" @@ -77,19 +81,17 @@ "Fonds d\'écran" "Paramètres d\'accueil" "Cette fonction est désactivée par votre administrateur" - "Présentation" - "Autoriser la rotation de l\'écran d\'accueil" - "Lorsque vous faites pivoter le téléphone" - "Le mode d\'affichage actuel ne permet pas le pivotement" "Points de notification" "Activé" "Désactivé" "L\'accès aux notifications est requis" "Pour afficher les points de notification, activez les notifications d\'application pour %1$s" "Modifier les paramètres" + "Afficher les points de notification" "Ajouter l\'icône à l\'écran d\'accueil" "Pour les nouvelles applications" "Modifier la forme de l\'icône" + "sur l\'écran d\'accueil" "Utiliser les valeurs système par défaut" "Carré" "Carré aux coins ronds" @@ -119,9 +121,6 @@ "Créer un dossier avec : %1$s" "Dossier créé" "Déplacer sur l\'écran d\'accueil" - "Déplacer l\'écran à gauche" - "Déplacer l\'écran à droite" - "Écran déplacé" "Redimensionner" "Augmenter la largeur" "Augmenter la hauteur" @@ -137,8 +136,9 @@ "Travail" "Profil professionnel" "Trouvez ici des applications professionnelles" - - + "Chaque application professionnelle comporte un badge, ce qui signifie qu\'elle est sécurisée par votre organisation. Vous pouvez déplacer vos applications vers l\'écran d\'accueil afin d\'y accéder plus facilement." "Géré par votre organisation" "Les notifications et les applications sont désactivées" + "Fermer" + "Fermé" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index e0997fc85a..e1b758124d 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -40,9 +40,13 @@ "Aucune application ne correspond à la requête \"%1$s\"" "Rechercher plus d\'applications" "Notifications" + "Appui prolongé pour sélectionner un raccourci." + "Appuyez 2X et maintenez la pression pour choisir un raccourci ou utilisez les actions personnalisées" "Pas d\'espace libre sur cet écran d\'accueil." "Plus d\'espace disponible dans la zone de favoris." "Liste d\'applications" + "Liste des applications personnelles" + "Liste des applications professionnelles" "Accueil" "Supprimer" "Désinstaller" @@ -77,19 +81,17 @@ "Fonds d\'écran" "Paramètres de l\'écran d\'accueil" "Désactivé par votre administrateur" - "Vue d\'ensemble" - "Autoriser la rotation de l\'écran d\'accueil" - "Lorsque vous faites pivoter le téléphone" - "Le paramètre d\'affichage actuel n\'autorise pas la rotation." "Pastilles de notification" "Activé" "Désactivé" "Accès aux notifications requis" "Pour afficher les pastilles de notification, activez les notifications de l\'application %1$s" "Modifier les paramètres" + "Afficher les pastilles de notification" "Ajouter l\'icône à l\'écran d\'accueil" "Pour les nouvelles applications" "Modifier la forme des icônes" + "sur l\'écran d\'accueil" "Utiliser la valeur système par défaut" "Carré" "Squircle" @@ -119,9 +121,6 @@ "Créer un dossier avec \"%1$s\"" "Dossier créé" "Déplacer vers l\'écran d\'accueil" - "Déplacer l\'écran vers la gauche" - "Déplacer l\'écran vers la droite" - "L\'écran a bien été déplacé." "Redimensionner" "Augmenter la largeur" "Augmenter la hauteur" @@ -137,8 +136,9 @@ "Professionnelles" "Profil professionnel" "Retrouvez ici vos applications professionnelles" - - + "Les applications professionnelles sont accompagnées d\'un badge et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement." "Géré par votre organisation" "Les notifications et les applications sont désactivées" + "Fermer" + "Fermé" diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 9feb1bd3b6..0cfdfa8991 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -40,10 +40,8 @@ "Non se atoparon aplicacións que coincidan con \"%1$s\"" "Buscar máis aplicacións" "Notificacións" - - - - + "Mantén premido un atallo para seleccionalo." + "Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas." "Non hai máis espazo nesta pantalla de inicio." "Non hai máis espazo na bandexa de favoritos" "Lista de aplicacións" @@ -142,5 +140,5 @@ "Perfil xestionado pola túa organización" "As notificacións e as aplicacións están desactivadas" "Pechar" - "Pechado" + "Pechada" diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index 53627180ab..efc953c809 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી" "વધુ ઍપ્લિકેશનો શોધો" "નોટિફિકેશનો" - - - - + "એક શૉર્ટકટ ચૂંટવા માટે સ્પર્શ કરી રાખો." + "એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરીને દબાવી રાખો." "આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી." "મનપસંદ ટ્રે પર વધુ જગ્યા નથી" "ઍપ્લિકેશનોની સૂચિ" @@ -141,8 +139,6 @@ "દરેક કાર્ય ઍપ પાસે એક બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો." "તમારી સંસ્થા દ્વારા મેનેજ કરેલ" "નોટિફિકેશન અને ઍપ બંધ છે" - - - - + "બંધ કરો" + "બંધ" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 15a4deb945..f98859df8c 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -40,9 +40,13 @@ "\"%1$s\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला" "और ऐप सर्च करें" "सूचनाएं" + "शॉर्टकट चुनने के लिए दबाकर रखें." + "शॉर्टकट चुनने या पसंद के मुताबिक कार्रवाई करने के लिए दो बार टैप करें और कुछ देर दबाए रखें." "इस होम स्‍क्रीन पर जगह नहीं बची है" "पसंदीदा ट्रे में और जगह नहीं है" "ऐप्लिकेशन सूची" + "निजी ऐप्लिकेशन की सूची" + "काम से जुड़े ऐप्लिकेशन की सूची" "होम पेज" "निकालें" "अनइंस्टॉल करें" @@ -77,19 +81,17 @@ "वॉलपेपर" "होम पेज की सेटिंग" "आपके एडमिन ने बंद किया हुआ है" - "खास जानकारी" - "होमस्क्रीन घुमाने की अनुमति दें" - "फ़ोन घुुमाए जाने पर" - "इस डिसप्ले सेटिंग में रोटेशन (स्क्रीन पर सामग्री को घुमाकर देखने) की सुविधा काम नहीं करती" "सूचना बिंदु" "चालू" "बंद" "सूचना के एक्सेस की ज़रूरत है" "सूचना बिंदु दिखाने के लिए, %1$s के ऐप्लिकेशन सूचना चालू करें" "सेटिंग बदलें" + "नए नोटिफ़िकेशन बताने वाला गोल निशान दिखाएं" "होम स्क्रीन में आइकॉन जोड़ें" "नए ऐप के लिए" "आइकॉन का आकार बदलें" + "होम स्‍क्रीन पर" "सिस्टम डिफ़ॉल्ट का उपयोग करें" "वर्ग" "गोल कोनों वाला वर्ग" @@ -119,9 +121,6 @@ "इसके साथ फ़ोल्डर बनाएं: %1$s" "फ़ोल्डर बनाया गया" "होम स्क्रीन पर ले जाएं" - "स्क्रीन को बाएं ले जाएं" - "स्क्रीन को दाएं ले जाएं" - "स्क्रीन ले जाई गई" "आकार बदलें" "चौड़ाई बढ़ाएं" "ऊंचाई बढ़ाएं" @@ -137,8 +136,9 @@ "काम से जुड़े ऐप" "कार्य प्रोफ़ाइल" "काम से जुड़े सभी ऐप्लिकेशन यहां पाएं" - - + "काम से जुड़े हर ऐप्लिकेशन पर एक बैज (निशान) होता है और इन ऐप्लिकेशन की सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं." "आपका संगठन प्रबंधित कर रहा है" "सूचनाएं और ऐप्लिकेशन बंद हैं" + "बंद करें" + "बंद कर दिया गया" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index d28c108b1b..35a7963936 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -40,9 +40,13 @@ "Nema aplikacija podudarnih s upitom \"%1$s\"" "Traži više aplikacija" "Obavijesti" + "Dodirnite i zadržite kako biste podigli prečac." + "Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama." "Na ovom početnom zaslonu više nema mjesta." "Nema više prostora na traci Favoriti" "Popis aplikacija" + "Popis osobnih aplikacija" + "Popis radnih aplikacija" "Početna" "Ukloni" "Deinstaliraj" @@ -78,19 +82,17 @@ "Pozadine" "Postavke Homea" "Onemogućio administrator" - "Pregled" - "Dopusti zakretanje početnog zaslona" - "Kada se telefon zakrene" - "Trenutačna postavka zaslona ne dopušta zakretanje" "Točke obavijesti" "Uključeno" "Isključeno" "Potreban je pristup obavijestima" "Za prikaz točaka obavijesti uključite obavijesti aplikacije %1$s" "Promjena postavki" + "Prikaži točke obavijesti" "Dodaj ikonu na početni zaslon" "Za nove aplikacije" "Promijeni oblik ikona" + "na početnom zaslonu" "Upotrijebi zadane postavke sustava" "Kvadrat" "Zaobljeni kvadrat" @@ -120,9 +122,6 @@ "Izrada mape pomoću stavke: %1$s" "Mapa izrađena" "Premještanje na početni zaslon" - "Premještanje zaslona ulijevo" - "Premještanje zaslona udesno" - "Zaslon je premješten" "Promjena veličine" "Povećanje širine" "Povećanje visine" @@ -138,8 +137,9 @@ "Posao" "Radni profil" "Ovdje možete pronaći radne aplikacije" - - + "Svaka radna aplikacija ima značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa." "Pod upravljanjem vaše organizacije" "Obavijesti i aplikacije isključeni su" + "Zatvori" + "Zatvoreno" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 997918bca4..4972e81924 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -40,10 +40,8 @@ "Nem található alkalmazás a(z) „%1$s” lekérdezésre" "További alkalmazások keresése" "Értesítések" - - - - + "Felvételhez tartsa nyomva a parancsikont." + "Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket." "Nincs több hely ezen a kezdőképernyőn." "Nincs több hely a Kedvencek tálcán" "Alkalmazások listája" diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index e233a4404a..8c3ae2591d 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -40,9 +40,13 @@ %1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել" "Որոնել այլ հավելվածներ" "Ծանուցումներ" + "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։" + "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:" "Այլևս տեղ չկա այս հիմնական էկրանին:" "Ընտրյալների ցուցակում այլևս ազատ տեղ չկա" "Հավելվածների ցանկ" + "Անձնական հավելվածների ցանկ" + "Աշխատանքային հավելվածների ցանկ" "Հիմնական" "Հեռացնել" "Հեռացնել" @@ -77,19 +81,17 @@ "Պաստառներ" "Գլխավոր էջի կարգավորումներ" "Անջատվել է ձեր ադմինիստրատորի կողմից" - "Համատեսք" - "Թույլ տալ հիմնական էկրանի պտտումը" - "Հեռախոսը պտտելու դեպքում" - "Ցուցադրման ընթացիկ կարգավորումներն արգելում են պտտումը" "Ծանուցումների կետիկներ" "Միացված է" "Անջատված է" "Անհրաժեշտ է ծանուցման թույլտվություն" "Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները %1$s-ի համար" "Փոխել կարգավորումները" + "Ցուցադրել ծանուցումների կետիկները" "Ավելացնել պատկերակը Հիմնական էկրանին" "Նոր հավելվածների համար" "Փոխել պատկերակների տեսքը" + "հիմնական էկրանին" "Օգտագործել համակարգի կանխադրված կարգավորումը" "Քառակուսի" "Քառանկյուն" @@ -119,9 +121,6 @@ "Ստեղծել թղթապանակ, օգտագործելով՝ %1$s" "Պանակը ստեղծվեց" "Տեղափոխել Հիմնական էկրան" - "Տեղափոխել էկրանը ձախ" - "Տեղափոխել էկրանը աջ" - "Էկրանը տեղափոխվեց" "Չափափոխել" "Ավելացնել լայնությունը" "Ավելացնել բարձրությունը" @@ -137,8 +136,9 @@ "Աշխատանքային" "Աշխատանքային պրոֆիլ" "Գտեք աշխատանքային հավելվածներ այստեղ" - - + "Աշխատանքային հավելվածները նշված են հատուկ նշանով: Նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։" "Կառավարվում է ձեր կազմակերպության կողմից" "Ծանուցումներն ու հավելվածներն անջատված են" + "Փակել" + "Փակվեց" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 29a15f5376..ea0ea4af12 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -40,10 +40,8 @@ "Tidak ditemukan aplikasi yang cocok dengan \"%1$s\"" "Telusuri aplikasi lainnya" "Notifikasi" - - - - + "Tap lama untuk memilih pintasan." + "Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus." "Tidak ada ruang lagi pada layar Utama ini." "Tidak ada ruang tersisa di baki Favorit" "Daftar aplikasi" diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index 1e89142cb1..3dc2d22118 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -40,9 +40,13 @@ "Ekki fundust forrit sem samsvara „%1$s“" "Leita að fleiri forritum" "Tilkynningar" + "Haltu fingri á flýtileið til að grípa hana." + "Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir." "Ekki meira pláss á þessum heimaskjá." "Ekki meira pláss í bakka fyrir uppáhald" "Forritalisti" + "Listi yfir eigin forrit" + "Listi yfir vinnuforrit" "Heim" "Fjarlægja" "Fjarlægja" @@ -77,19 +81,17 @@ "Veggfóður" "Heimastillingar" "Gert óvirkt af kerfisstjóra" - "Yfirlit" - "Leyfa snúning fyrir heimaskjá" - "Þegar símanum er snúið" - "Núverandi skjástilling leyfir ekki snúning" "Tilkynningapunktar" "Kveikt" "Slökkt" "Aðgangs að tilkynningum er krafist" "Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir %1$s" "Breyta stillingum" + "Sýna tilkynningapunkta" "Bæta tákni á heimaskjáinn" "Fyrir ný forrit" "Breyta formi tákns" + "á heimaskjá" "Nota sjálfgildi kerfis" "Ferningur" "Ferhringur" @@ -119,9 +121,6 @@ "Búa til möppu með: %1$s" "Mappa búin til" "Færa á heimaskjá" - "Færa skjá til vinstri" - "Færa skjá til hægri" - "Skjár færður" "Breyta stærð" "Auka breidd" "Auka hæð" @@ -137,8 +136,9 @@ "Vinna" "Vinnusnið" "Hér finnurðu vinnuforrit" - - + "Öll vinnuforrit eru með merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn til að fá auðveldari aðgang að þeim." "Stjórnað af fyrirtækinu þínu" "Slökkt er á tilkynningum og forritum" + "Loka" + "Lokað" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 03f98aebd7..44e12c0e40 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -40,10 +40,8 @@ "Nessuna app trovata corrispondente a \"%1$s\"" "Cerca altre app" "Notifiche" - - - - + "Tocca e tieni premuto per scegliere la scorciatoia" + "Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate." "Spazio nella schermata Home esaurito." "Spazio esaurito nella barra dei Preferiti" "Elenco di app" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 961bd01117..bc2061ba28 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -40,9 +40,13 @@ "לא נמצאו אפליקציות התואמות ל-\"%1$s\"" "חפש אפליקציות נוספות" "הודעות" + "כדי להוסיף קיצור דרך, יש לגעת בו ולהחזיק אותו." + "כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, יש להקיש על קיצור הדרך פעמיים ולהחזיק אותו." "אין עוד מקום במסך דף הבית הזה." "אין עוד מקום במגש המועדפים" "רשימת אפליקציות" + "רשימת אפליקציות אישיות" + "רשימת אפליקציות עבודה" "דף הבית" "הסר" "הסר התקנה" @@ -79,19 +83,17 @@ "טפטים" "הגדרות דף הבית" "הושבת על ידי מנהל המערכת שלך" - "סקירה" - "אפשרות סיבוב של מסך דף הבית" - "כאשר הטלפון מסובב" - "הגדרת התצוגה הנוכחית אינה מאפשרת סיבוב" "סימני הודעות" "מופעלת" "כבויה" "נדרשת גישה להודעות" "כדי להציג את סימני ההודעות, יש להפעיל הודעות מהאפליקציה %1$s" "שנה את ההגדרות" + "הצגה של סימן ההודעות" "הוספת סמל במסך דף הבית" "לאפליקציות חדשות" "שינוי הצורה של הסמלים" + "במסך דף הבית" "השתמש בברירת המחדל של המערכת" "ריבוע" "ריבוע בעל פינות מעוגלות" @@ -121,9 +123,6 @@ "צור תיקייה עם: %1$s" "התיקייה נוצרה" "העבר אל מסך דף הבית" - "הזז את המסך שמאלה" - "הזז את המסך ימינה" - "המסך הועבר" "שנה גודל" "הגדל רוחב" "הגדל גובה" @@ -139,8 +138,9 @@ "עבודה" "פרופיל עבודה" "ניתן למצוא כאן את אפליקציות העבודה" - - + "לכל אפליקציית עבודה יש תג ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן." "מנוהל בידי הארגון" "הודעות ואפליקציות כבויות" + "סגירה" + "סגור" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 19a9d3cbcc..c5ab31039c 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -40,10 +40,8 @@ "「%1$s」に一致するアプリは見つかりませんでした" "他のアプリを検索" "通知" - - - - + "ショートカットを追加するには押し続けます。" + "ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。" "このホーム画面に空きスペースがありません。" "お気に入りトレイに空きスペースがありません" "アプリのリスト" diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index c9d4d26cf9..02ca8628ed 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -40,10 +40,8 @@ "„%1$s“-ის თანხვედრი აპები არ მოიძებნა" "მეტი აპის პოვნა" "შეტყობინებები" - - - - + "შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად." + "ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად." "ამ მთავარ ეკრანზე ადგილი აღარ არის." "რჩეულების თაროზე ადგილი არ არის" "აპების სია" diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 8a05cc0919..b66fe69a39 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" сұрауына сәйкес келетін қолданбалар жоқ" "Қосымша қолданбалар іздеу" "Хабарландырулар" - - - - + "Таңбашаны таңдау үшін оны басып, ұстап тұрыңыз." + "Екі рет басып, ұстап тұрып, таңбашаны таңдаңыз немесе арнаулы әрекеттерді пайдаланыңыз." "Бұл Негізгі экранда орын қалмады." "Қалаулылар науасында орын қалмады" "Қолданбалар тізімі" diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index 9b7fa87c23..6b56372160 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -40,10 +40,8 @@ "រកមិនឃើញកម្មវិធី​ដែលត្រូវគ្នាជាមួយ \"%1$s\" ទេ" "ស្វែងរកកម្មវិធីច្រើនទៀត" "ការ​ជូនដំណឹង" - - - - + "ចុច​ឱ្យ​ជាប់​ដើម្បី​ជ្រើស​រើស​ផ្លូវកាត់​មួយ។" + "ចុច​ពីរ​ដង ហើយ​ចុច​ឱ្យ​ជាប់​ដើម្បី​ជ្រើសរើស​ផ្លូវកាត់​មួយ ឬ​ប្រើ​សកម្មភាព​ផ្ទាល់ខ្លួន។" "គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​នេះ​ទៀត​ទេ។" "គ្មាន​បន្ទប់​​ក្នុង​ថាស​និយម​ប្រើ" "បញ្ជីកម្មវិធី" diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 0e314bb121..d4813b5760 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ" "ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಹುಡುಕಿ" "ಅಧಿಸೂಚನೆಗಳು" - - - - + "ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ." + "ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ." "ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ." "ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ" "ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ" @@ -141,8 +139,6 @@ "ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸರಿಸಿ." "ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ" "ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಆಫ್ ಆಗಿವೆ" - - - - + "ಮುಚ್ಚಿ" + "ಮುಚ್ಚಲಾಗಿದೆ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 60c3e4f6b4..9275abfe1f 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -40,10 +40,8 @@ "\'%1$s\'과(와) 일치하는 앱이 없습니다." "더 많은 앱 검색" "알림" - - - - + "바로가기를 선택하려면 길게 터치하세요." + "바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 동작을 사용하세요." "홈 화면에 더 이상 공간이 없습니다." "즐겨찾기 트레이에 더 이상 공간이 없습니다." "앱 목록" diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index 84bee66e31..e0e740346a 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" сурамына дал келген колдонмолор табылган жок" "Көбүрөөк колдонмолорду издөө" "Эскертмелер" - - - - + "Кыска жолду тандоо үчүн басып туруңуз." + "Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз." "Бул Үй экранында бош орун жок." "Тандамалдар тайпасында орун калган жок" "Колдонмолор тизмеси" diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index bd89e6e926..2b73628978 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -40,10 +40,8 @@ "ບໍ່ພົບແອັບທີ່ກົງກັບ \"%1$s\"" "ຊອກຫາແອັບເພີ່ມເຕີມ" "ການແຈ້ງເຕືອນ" - - - - + "ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ." + "ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ." "ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້." "ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ" "ລາຍຊື່ແອັບ" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 3e985cb094..db751dae6a 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -40,9 +40,13 @@ "Nerasta jokių užklausą „%1$s“ atitinkančių programų" "Ieškoti daugiau programų" "Pranešimai" + "Paliesk. ir palaikyk., kad pasirinkt. spart. klav." + "Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus." "Šiame pagrindiniame ekrane vietos nebėra." "Mėgstamiausių dėkle nebėra vietos" "Programų sąrašas" + "Asmeninių programų sąrašas" + "Darbo programų sąrašas" "Pagrindinis" "Ištrinti" "Pašalinti" @@ -79,19 +83,17 @@ "Ekrano fonai" "„Home“ nustatymai" "Išjungė administratorius" - "Apžvalga" - "Leisti pasukti pagrindinį ekraną" - "Kai telefonas pasukamas" - "Naudojant dabartinį pateikties nustatymą neleidžiama pasukti" "Pranešimų taškai" "Įjungta" "Išjungta" "Reikalinga prieiga prie pranešimų" "Kad būtų rodomi pranešimų taškai, įjunkite programos „%1$s“ pranešimus." "Keisti nustatymus" + "Rodyti pranešimų taškus" "Pridėti piktogr. prie pagrindinio ekrano" "Skirta naujoms programoms" "Pakeisti piktogramos formą" + "pagrindiniame ekrane" "Naudoti numatytuosius sistemos nustatymus" "Kvadratas" "Kvadratais suapvalintais kampais" @@ -121,9 +123,6 @@ "Kurti aplanką naudojant: „%1$s“" "Aplankas sukurtas" "Perkelti į pagrindinį ekraną" - "Perkelti ekraną į kairę" - "Perkelti ekraną į dešinę" - "Ekranas perkeltas" "Pakeisti dydį" "Padidinti plotį" "Padidinti aukštį" @@ -139,8 +138,9 @@ "Darbo" "Darbo profilis" "Darbo programas rasite čia" - - + "Kiekvienai darbo programai priskirtas ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti." "Tvarko jūsų organizacija" "Programos ir pranešimai išjungti" + "Uždaryti" + "Uždaryta" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 6a9d15791b..a6e16deeef 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -40,9 +40,13 @@ "Vaicājumam “%1$s” neatbilda neviena lietotne" "Meklēt citas lietotnes" "Paziņojumi" + "Lai atlasītu saīsni, pieskarieties un turiet to." + "Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to. Varat arī veikt pielāgotas darbības." "Šajā sākuma ekrānā vairs nav vietas." "Izlases joslā vairs nav vietas." "Lietotņu saraksts" + "Personīgo lietotņu saraksts" + "Darba lietotņu saraksts" "Sākums" "Noņemt" "Atinstalēt" @@ -78,19 +82,17 @@ "Fona tapetes" "Sākumlapas iestatījumi" "Atspējojis administrators" - "Kopsavilkums" - "Atļaut sākuma ekrāna pagriešanu" - "Pagriežot tālruni" - "Pašreizējā displeja iestatījumā nav atļauta pagriešana." "Paziņojumu punkti" "Ieslēgts" "Izslēgts" "Nepieciešama piekļuve paziņojumiem" "Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei %1$s." "Mainīt iestatījumus" + "Rādīt paziņojumu punktus" "Pievienot ikonu sākuma ekrānā" "Jaunām lietotnēm" "Mainīt ikonu formu" + "sākuma ekrānā" "Izmantot sistēmas noklusējumu" "Kvadrāts" "Kvadrāts ar noapaļotiem stūriem" @@ -120,9 +122,6 @@ "Izveidot mapi ar: %1$s" "Mape izveidota" "Pārvietot uz sākuma ekrānu" - "Pārvietot ekrānu pa kreisi" - "Pārvietot ekrānu pa labi" - "Ekrāns pārvietots" "Mainīt lielumu" "Palielināt platumu" "Palielināt augstumu" @@ -138,8 +137,9 @@ "Darba lietotnes" "Darba profils" "Meklējiet darba lietotnes šeit" - - + "Katrai darba lietotnei ir emblēma, un jūsu organizācija aizsargā šīs lietotnes. Lai varētu ērtāk piekļūt lietotnēm, pārvietojiet tās uz sākuma ekrānu." "Pārvalda jūsu organizācija" "Paziņojumi un lietotnes ir izslēgtas" + "Aizvērt" + "Aizvērta" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 9eedfeb881..29e837b27c 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -40,10 +40,8 @@ "Не се најдени апликации што одговараат на „%1$s“" "Пребарај други апликации" "Известувања" - - - - + "Допрете двапати и задржете за избор на кратенка." + "Допрете двапати и задржете за избор на кратенка или користете приспособени дејства." "Нема повеќе простор на овој екран на почетната страница." "Нема повеќе простор на лентата „Омилени“" "Список со апликации" diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 9455688038..5ccac13e4a 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല" "കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക" "അറിയിപ്പുകൾ" - - - - + "തിരഞ്ഞെടുക്കുന്നതിന് കുറുക്കുവഴി സ്‌പർശിച്ച് പിടിക്കുക." + "കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്‌ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ 2 തവണ ടാപ്പ് ചെയ്‌ത് പിടിക്കുക." "ഈ ഹോം സ്‌ക്രീനിൽ ഒഴിവൊന്നുമില്ല." "പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല" "അപ്ലിക്കേഷനുകളുടെ ലിസ്‌റ്റ്" @@ -141,8 +139,6 @@ "എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഒരു ബാഡ്‌ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക." "നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്" "അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്" - - - - + "അടയ്ക്കുക" + "അടച്ചു" diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index 7d0c0ef2ca..7c0b00ec7b 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\"-д тохирох апп олдсонгүй" "Бусад апп-г хайх" "Мэдэгдэл" - - - - + "Товчлол авах бол удаан дарна уу." + "Товчлол авах эсвэл тохируулсан үйлдлийг ашиглахын тулд давхар товшоод хүлээнэ үү." "Энэ Нүүр дэлгэц зайгүй." "\"Дуртай\" трей дээр өөр зай байхгүй байна" "Апп-н жагсаалт" diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index d843d37082..0e2f9c808c 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत" "अधिक अॅप्स शोधा" "सूचना" - - - - + "शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा." + "शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा." "या मुख्य स्क्रीनवर आणखी जागा नाही." "आवडीच्या ट्रे मध्ये आणखी जागा नाही" "अॅप्स सूची" @@ -141,8 +139,6 @@ "प्रत्येक कार्य अ‍ॅपला एक बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अ‍ॅक्सेससाठी अ‍ॅप्स तुमच्या होम स्क्रीनवर हलवा." "तुमच्या संस्थेकडून व्यवस्थापित" "सूचना आणि अॅप्स बंद आहेत" - - - - + "बंद करा" + "बंद केले" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index d403de0629..130e008389 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -40,10 +40,8 @@ "Tiada apl yang ditemui sepadan dengan \"%1$s\"" "Cari lagi apl" "Pemberitahuan" - - - - + "Sentuh & tahan untuk mengambil pintasan." + "Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai." "Tiada lagi ruang pada skrin Laman Utama ini." "Tiada ruang dalam dulang Kegemaran lagi" "Senarai apl" diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 3c2d91f572..778402ac27 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ" "နောက်ထပ် အက်ပ်များကို ရှာပါ" "အကြောင်းကြားချက်များ" - - - - + "ဖြတ်လမ်းလင့်ခ်တစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ။" + "ဖြတ်လမ်းလင့်ခ်ကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။" "ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ" "အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ" "အက်ပ်စာရင်း" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index f7cac37dad..5542079640 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -40,10 +40,8 @@ "Fant ingen apper som samsvarer med «%1$s»" "Søk etter flere apper" "Varsler" - - - - + "Trykk og hold for å velge en snarvei." + "Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger." "Denne startsiden er full." "Favoritter-skuffen er full" "App-liste" diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index e7990c88b7..fa2f9cf0b8 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन" "थप अनुप्रयोगहरू खोज्नुहोस्" "सूचनाहरू" - - - - + "कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।" + "कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।" "यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।" "मनपर्ने ट्रे अब कुनै ठाँउ छैन" "अनुप्रयोगको सूची" @@ -141,8 +139,6 @@ "कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा ब्याज छ र तपाईंको संगठनले यसलाई सुरक्षित राखेको छ । अझ सजिलो गरी पहुँच राख्नका लागि अनुप्रयोगहरूलाई आफ्नो गृहस्क्रिनमा सार्नुहोस्‌।" "तपाईंको सङ्गठनले व्यवस्थापन गरेको" "सूचना र अनुप्रयोगहरू निष्क्रिय छन्‌" - - - - + "बन्द गर्नुहोस्" + "बन्द गरियो" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index b926a8d747..458b6dd993 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -40,10 +40,8 @@ "Er zijn geen apps gevonden die overeenkomen met \'%1$s\'" "Zoeken naar meer apps" "Meldingen" - - - - + "Tik en houd vast om snelkoppeling toe te voegen." + "Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken." "Er is geen ruimte meer op dit startscherm." "Geen ruimte meer in het vak \'Favorieten\'" "Lijst met apps" diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 26de62ac6b..02424031bf 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ" "ਹੋਰ ਐਪਾਂ ਖੋਜੋ" "ਸੂਚਨਾਵਾਂ" - - - - + "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।" + "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।" "ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।" "ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।" "ਐਪ ਸੂਚੀ" @@ -141,8 +139,6 @@ "ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।" "ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ" "ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ" - - - - + "ਬੰਦ ਕਰੋ" + "ਬੰਦ ਕੀਤਾ ਗਿਆ" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index e9b4cc93d8..558fab2590 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -40,6 +40,8 @@ "Nie znaleziono aplikacji pasujących do zapytania „%1$s”" "Wyszukaj więcej aplikacji" "Powiadomienia" + "Kliknij i przytrzymaj, by wybrać skrót." + "Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych." "Brak miejsca na tym ekranie głównym." "Brak miejsca w Ulubionych" "Lista aplikacji" @@ -139,4 +141,6 @@ "Każda aplikacja do pracy ma plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne." "Profil zarządzany przez Twoją organizację" "Powiadomienia i aplikacje są wyłączone" + "Zamknij" + "Zamknięto" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 9517baf035..0d3224d39d 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -40,10 +40,8 @@ "Nenhuma aplicação correspondente a \"%1$s\"" "Pesquisar mais aplicações" "Notificações" - - - - + "Toque sem soltar para escolher um atalho." + "Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas." "Sem espaço suficiente neste Ecrã principal." "Não existe mais espaço no tabuleiro de Favoritos" "Lista de aplicações" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 48e37efb64..73dad35bbb 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -40,9 +40,13 @@ "Nenhum app encontrado que corresponda a \"%1$s\"" "Pesquisar mais apps" "Notificações" + "Toque e segure para selecionar um atalho." + "Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas." "Não há mais espaço na tela inicial." "Sem espaço na bandeja de favoritos" "Lista de apps" + "Lista de apps pessoais" + "Lista de apps profissionais" "Início" "Remover" "Desinstalar" @@ -77,19 +81,17 @@ "Planos de fundo" "Configurações da página inicial" "Desativado pelo administrador" - "Visão geral" - "Permitir rotação da tela inicial" - "Quando o smartphone for girado" - "A configuração atual de exibição não permite rotação" "Pontos de notificação" "Ativado" "Desativado" "Acesso a notificações necessário" "Para mostrar pontos de notificação, ative as notificações de app para %1$s" "Alterar configurações" + "Mostrar pontos de notificação" "Adicionar ícone à tela inicial" "Para novos apps" "Alterar forma de ícones" + "na tela inicial" "Usar padrão do sistema" "Quadrado" "Quadrado arredondado" @@ -119,9 +121,6 @@ "Criar pasta com: %1$s" "Pasta criada" "Mover para a tela inicial" - "Mover tela para a esquerda" - "Mover tela para a direita" - "Tela movida" "Redimensionar" "Aumentar largura" "Aumentar altura" @@ -137,8 +136,9 @@ "Comerciais" "Perfil de trabalho" "Localizar apps de trabalho aqui" - - + "Cada app de trabalho tem um selo e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso." "Gerenciados pela sua organização" "As notificações e os apps estão desativados" + "Fechar" + "Fechado" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 88118d9fe7..500512ac31 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -40,10 +40,8 @@ "Nu s-a găsit nicio aplicație pentru „%1$s\"" "Căutați mai multe aplicații" "Notificări" - - - - + "Atingeți lung pentru a selecta o comandă rapidă." + "Atingeți lung pentru a selecta o comandă rapidă sau folosiți acțiuni personalizate." "Nu mai este loc pe acest Ecran de pornire." "Spațiu epuizat în bara Preferate" "Lista de aplicații" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 10490f38b5..d04ca5c04a 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -40,9 +40,13 @@ "По запросу \"%1$s\" ничего не найдено" "Искать другие приложения" "Уведомления" + "Нажмите и удерживайте, чтобы выбрать ярлык." + "Нажмите дважды и удерживайте, чтобы выбрать ярлык или использовать специальные действия." "На этом экране все занято" "В разделе \"Избранное\" больше нет места" "Список приложений" + "Открыть список личных приложений" + "Открыть список приложений для работы" "Главный экран" "Убрать" "Удалить" @@ -79,19 +83,17 @@ "Обои" "Настройки главного экрана" "Функция отключена администратором" - "Обзор" - "Разрешить поворачивать главный экран" - "Когда телефон повернут" - "В настройках отключен поворот экрана" "Значки уведомлений" "ВКЛ" "ВЫКЛ" "Нет доступа к уведомлениям" "Чтобы показывать значки уведомлений, включите уведомления в приложении \"%1$s\"" "Изменить настройки" + "Показывать значки уведомлений" "Добавлять значки" "Добавлять значки установленных приложений на главный экран." "Изменить форму значков" + "на главном экране" "Использовать системные настройки по умолчанию" "Квадрат" "Квадрат с закругленными краями" @@ -121,9 +123,6 @@ "Создать папку с элементом %1$s." "Папка создана." "Переместить на главный экран" - "Переместить экран влево" - "Переместить экран вправо" - "Экран перемещен" "Изменить размер" "Увеличить ширину" "Увеличить высоту" @@ -139,8 +138,9 @@ "Рабочие" "Рабочий профиль" "Приложения для работы" - - + "Рабочие приложения отмечены специальным значком. Их безопасность обеспечивает ваша организация. Для удобства перенесите эти приложения на главный экран." "Управляется вашей организацией" "Уведомления и приложения отключены." + "Закрыть" + "Закрыта" diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index f1ffba4a4b..7a4771e611 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි" "තව යෙදුම් සඳහා සොයන්න" "දැනුම්දීම්" - - - - + "කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න." + "විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න." "මෙම මුල් පිටු තිරය මත තවත් අවසර නැත." "ප්‍රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත" "යෙදුම් ලැයිස්තුව" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 546787f9a5..4d90dee09f 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -40,10 +40,8 @@ "Nenašli sa žiadne aplikácie zodpovedajúce dopytu %1$s" "Hľadať ďalšie aplikácie" "Upozornenia" - - - - + "Skratku pridáte pridržaním." + "Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií." "Na tejto ploche už nie je miesto" "Na paneli Obľúbené položky už nie je miesto" "Zoznam aplikácií" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 488295e9d4..82b79125b4 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -40,10 +40,8 @@ "Ni aplikacij, ki bi ustrezale poizvedbi »%1$s«" "Iskanje več aplikacij" "Obvestila" - - - - + "Pridržite bližnjico, da jo izberete." + "Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri." "Na tem začetnem zaslonu ni več prostora." "V vrstici za priljubljene ni več prostora" "Seznam aplikacij" diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 8d58d1c2de..a4ad7a0543 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -40,10 +40,8 @@ "Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\"" "Kërko për më shumë aplikacione" "Njoftimet" - - - - + "Prek dhe mbaj prekur për të zgjedhur një shkurtore." + "Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara." "Nuk ka më hapësirë në këtë ekran bazë." "Nuk ka më hapësirë në tabakanë \"Të preferuarat\"" "Lista e aplikacioneve" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index c190e758e1..3ae87f9e55 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -40,9 +40,13 @@ "Није пронађена ниједна апликација за „%1$s“" "Претражи још апликација" "Обавештења" + "Додирните и задржите да бисте изабрали пречицу." + "Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње." "Нема више простора на овом почетном екрану." "Нема више простора на траци Омиљено" "Листа апликација" + "Листа личних апликација" + "Листа пословних апликација" "Почетна" "Уклони" "Деинсталирај" @@ -78,19 +82,17 @@ "Позадине" "Подешавања почетног екрана" "Администратор је онемогућио" - "Преглед" - "Дозволи ротацију почетног екрана" - "Када се телефон ротира" - "Актуелно подешавање приказа не дозвољава ротацију" "Тачке за обавештења" "Укључено" "Искључено" "Потребан је приступ за обавештења" "Да бисте приказали тачке за обавештења, укључите обавештења за апликацију %1$s" "Промените подешавања" + "Приказуј тачке за обавештења" "Додај икону на почетни екран" "За нове апликације" "Промените облик икона" + "на почетном екрану" "Користи подразумевано системско подешавање" "Квадрат" "Заобљени квадрат" @@ -120,9 +122,6 @@ "Направите директоријум са: %1$s" "Директоријум је направљен" "Премести на почетни екран" - "Помери екран улево" - "Помери екран удесно" - "Екран је померен" "Промени величину" "Повећај ширину" "Повећај висину" @@ -138,8 +137,9 @@ "Пословне" "Профил за Work" "Пронађите пословне апликације овде" - - + "Свака пословна апликација има значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали." "Овим управља организација" "Обавештења и апликације су искључени" + "Затвори" + "Затворено" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index e58e1987a7..3c91c30b66 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -40,10 +40,8 @@ "Inga appar som matchar %1$s hittades" "Sök efter fler appar" "Aviseringar" - - - - + "Tryck länge om du vill ta upp en genväg." + "Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder." "Det finns inte plats för mer på den här startskärmen." "Favoritfältet är fullt" "Applista" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 80666e97c2..61d7f8bed3 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -40,10 +40,8 @@ "Haikupata programu zozote zinazolingana na \"%1$s\"" "Tafuta programu zaidi" "Arifa" - - - - + "Gusa na ushikilie ili uchague njia ya mkato." + "Gusa mara mbili na ushikilie ili uchague njia ya mkato au utumie vitendo maalum." "Hakuna nafasi katika skrini hii ya Mwanzo." "Hakuna nafasi zaidi katika treya ya Vipendeleo" "Orodha ya programu" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 8a7d66622e..13358c09ce 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -141,8 +141,6 @@ "ஒவ்வொரு பணிப் பயன்பாடும் ஒரு பேட்ஜைக் கொண்டிருக்கும். இவை, ஆப்ஸ் உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன என்பதைக் குறிக்கின்றன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்." "உங்கள் நிறுவனம் நிர்வகிக்கிறது" "ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன" - - - - + "மூடுக" + "மூடப்பட்டது" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index b69afdc4e6..3f1762d00d 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\"కి సరిపోలే అప్లికేషన్‌లేవీ కనుగొనబడలేదు" "మరిన్ని యాప్‌ల కోసం వెతుకు" "నోటిఫికేషన్‌లు" - - - - + "షార్ట్‌కట్‌ని ఎంచుకోవడం కోసం నొక్కి, పట్టుకోండి." + "రెండుసార్లు నొక్కి, పట్టుకోవడం ద్వారా షార్ట్‌కట్‌ని ఎంచుకోండి లేదా అనుకూల చర్యలను ఉపయోగించండి." "ఈ హోమ్ స్క్రీన్‌లో ఖాళీ లేదు." "ఇష్టమైనవి ట్రేలో ఖాళీ లేదు" "అనువర్తనాల జాబితా" @@ -141,8 +139,6 @@ "ప్రతి కార్యాలయ యాప్‌కు బ్యాడ్జ్‌ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్‌లను మీ హోమ్ స్క్రీన్‌కి తరలించండి." "మీ సంస్థ ద్వారా నిర్వహించబడతాయి" "నోటిఫికేషన్‌లు మరియు యాప్‌లు ఆఫ్ చేయబడ్డాయి" - - - - + "మూసివేయి" + "మూసివేయబడింది" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index c032305af8..cac2333509 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -40,10 +40,8 @@ "ไม่พบแอปที่ตรงกับ \"%1$s\"" "ค้นหาแอปเพิ่มเติม" "การแจ้งเตือน" - - - - + "แตะค้างไว้เพื่อเลือกทางลัด" + "แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง" "ไม่มีที่ว่างในหน้าจอหลักนี้" "ไม่มีพื้นที่เหลือในถาดรายการโปรด" "รายชื่อแอป" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index d0a820d917..0b90214225 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -40,9 +40,13 @@ "Walang nahanap na app na tumutugma sa \"%1$s\"" "Maghanap ng higit pang mga app" "Mga Notification" + "Pindutin nang matagal para kumuha ng shortcut." + "I-double tap nang matagal para kumuha ng shortcut o gumamit ng mga custom na pagkilos." "Wala nang lugar sa Home screen na ito." "Wala nang lugar sa tray ng Mga Paborito" "Listahan ng mga app" + "Listahan ng mga personal na app" + "Listahan ng mga app sa trabaho" "Home" "Alisin" "I-uninstall" @@ -77,19 +81,17 @@ "Mga Wallpaper" "Mga setting ng Home" "Na-disable ng iyong admin" - "Pangkalahatang-ideya" - "Payagan ang pag-rotate ng Home screen" - "Kailan maro-rotate ang telepono" - "Hindi pinahihintulutan ng kasalukuyang setting ng Display ang pag-rotate" "Mga notification dot" "Naka-on" "Naka-off" "Kinakailangan ng access sa notification" "Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa %1$s" "Baguhin ang mga setting" + "Ipakita ang mga notification dot" "Idagdag ang icon sa Home screen" "Para sa mga bagong app" "Baguhin ang hugis ng icon" + "sa Home screen" "Gamitin ang default ng system" "Parisukat" "Squircle" @@ -119,9 +121,6 @@ "Gumawa ng folder na may: %1$s" "Nagawa ang folder" "Ilipat sa Home screen" - "Ilipat sa kaliwa ang screen" - "Ilipat sa kanan ang screen" - "Nailipat ang screen" "I-resize" "Dagdagan ang lapad" "Dagdagan ang taas" @@ -137,8 +136,9 @@ "Trabaho" "Profile sa trabaho" "Maghanap ng mga app para sa trabaho rito" - - + "Ang bawat app para sa trabaho ay may badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access." "Pinamamahalaan ng iyong organisasyon" "Naka-off ang mga notification at app" + "Isara" + "Nakasara" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 22e6bda95f..972554424c 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" ile eşleşen uygulama bulunamadı" "Başka uygulamalar ara" "Bildirimler" - - - - + "Kısayol seçmek için dokunun ve basılı tutun." + "Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun." "Bu Ana ekranda yer kalmadı." "Favoriler tepsisinde başka yer kalmadı" "Uygulamalar listesi" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 095ff5ba30..47ddc7c944 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -40,9 +40,13 @@ "Немає додатків для запиту \"%1$s\"" "Шукати ще додатки" "Сповіщення" + "Натисніть і втримуйте, щоб вибрати ярлик." + "Двічі натисніть і втримуйте, щоб вибрати ярлик, або виконайте іншу дію." "На цьому головному екрані більше немає місця." "В області \"Вибране\" немає місця" "Список додатків" + "Список особистих додатків" + "Список робочих додатків" "Головний екран" "Видалити" "Видалити" @@ -79,19 +83,17 @@ "Фонові малюнки" "Налаштування Home" "Вимкнув адміністратор" - "Огляд" - "Дозволити обертання головного екрана" - "Коли телефон обертається" - "Поточні налаштування дисплея не підтримують обертання" "Значки сповіщень" "Увімкнено" "Вимкнено" "Потрібен доступ до сповіщень" "Щоб показувати значки сповіщень, увімкніть сповіщення в додатку %1$s" "Змінити налаштування" + "Показувати значки сповіщень" "Додати значок на головний екран" "Для нових додатків" "Змінити форму значка" + "на головному екрані" "Використовувати налаштування системи за умовчанням" "Квадрат" "Квадрат із заокругленими кутами" @@ -121,9 +123,6 @@ "Створити папку з: %1$s" "Папку створено" "Перемістити на головний екран" - "Перемістити екран ліворуч" - "Перемістити екран праворуч" - "Екран переміщено" "Змінити розміри" "Збільшити ширину" "Збільшити висоту" @@ -139,8 +138,9 @@ "Робочі додатки" "Робочий профіль" "Робочі додатки містяться тут" - - + "Кожний робочий додаток має значок і перебуває під захистом організації. Перенесіть додатки на головний екран, щоб швидко запускати їх." "Профілем керує ваша організація" "Сповіщення та додатки вимкнено" + "Закрити" + "Закрито" diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index 0344cc0d2f..2558076469 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -40,10 +40,8 @@ "\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں" "مزید ایپس تلاش کریں" "اطلاعات" - - - - + "ایک شارٹ کٹ منتخب کرنے کیلئے ٹچ کر کے دبائے رکھیں۔" + "ایک شارٹ کٹ منتخب کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔" "اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔" "پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے" "ایپس کی فہرست" @@ -141,8 +139,6 @@ "ہر دفتری ایپ میں ایک بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔" "آپ کی تنظیم کے زیر انتظام" "اطلاعات اور ایپس آف ہیں" - - - - + "بند کریں" + "بند" diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index ea4cf6d475..e9f36a842a 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -40,10 +40,8 @@ "“%1$s” bilan mos hech qanday ilova topilmadi" "Boshqa ilovalarni qidirish" "Bildirishnomalar" - - - - + "Yorliqni tanlab olish uchun bosib turing." + "Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning." "Uy ekranida bitta ham xona yo‘q." "Ajratilganlarda birorta ham xona yo‘q" "Ilovalar ro‘yxati" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 27a9f80d01..65a5eccf82 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -40,10 +40,8 @@ "Không tìm thấy ứng dụng nào phù hợp với \"%1$s\"" "Tìm kiếm thêm ứng dụng" "Thông báo" - - - - + "Chạm và giữ để chọn lối tắt." + "Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh." "Không còn chỗ trên Màn hình chính này." "Không còn chỗ trong khay Mục yêu thích" "Danh sách ứng dụng" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 694125711d..f8dd3cd05f 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -40,9 +40,13 @@ "未找到与“%1$s”相符的应用" "搜索更多应用" "通知" + "触摸并按住快捷方式即可选择快捷方式。" + "点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。" "此主屏幕上已没有空间。" "收藏栏已满" "应用列表" + "个人应用列表" + "工作应用列表" "主屏幕" "移除" "卸载" @@ -77,19 +81,17 @@ "壁纸" "主屏幕设置" "已被您的管理员停用" - "概览" - "允许旋转主屏幕" - "手机旋转时" - "当前的显示设置不允许旋转设备" "通知圆点" "开启" "关闭" "需要获取通知使用权" "要显示通知圆点,请开启%1$s的应用通知功能" "更改设置" + "显示通知圆点" "将图标添加到主屏幕" "适用于新应用" "更改图标形状" + "在主屏幕上" "使用系统默认设置" "方形" "方圆形" @@ -119,9 +121,6 @@ "创建“%1$s”文件夹" "文件夹已创建" "移至主屏幕" - "将屏幕向左移动" - "将屏幕向右移动" - "屏幕已移动" "调整大小" "增加宽度" "增加高度" @@ -137,8 +136,9 @@ "工作" "工作资料" "请在此处查找工作应用" - - + "每个工作应用均有一个徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。" "由贵单位管理" "通知和应用均已关闭" + "关闭" + "已关闭" diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 85d644af54..4828006cbb 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -40,10 +40,8 @@ "找不到與「%1$s」相符的應用程式" "搜尋更多應用程式" "通知" - - - - + "按住捷徑即可選取。" + "撳兩下之後撳住,就可以揀選捷徑或者用自訂嘅操作。" "主畫面已無空間。" "我的收藏寄存區沒有足夠空間" "應用程式清單" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 07917b649d..1a8d515348 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -40,10 +40,8 @@ "找不到與「%1$s」相符的應用程式" "搜尋更多應用程式" "通知" - - - - + "按住捷徑即可選取。" + "輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。" "這個主螢幕已無空間。" "「我的最愛」匣已無可用空間" "應用程式清單" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 323144bd23..126145eac5 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -40,9 +40,13 @@ "Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"%1$s\"" "Sesha izinhlelo zokusebenza eziningi" "Izaziso" + "Thinta futhi ubambe ukuze ukhethe isinqamuleli." + "Thepha kabili uphinde ubambe ukuze uphakamise isinqamuleli noma usebenzise izenzo zangokwezifiso." "Asisekho isikhala kulesi sikrini Sasekhaya." "Asisekho isikhala kwitreyi lezintandokazi" "Uhlu lwezinhlelo zokusebenza" + "Uhlu lwezinhlelo zokusebenza zomuntu siqu" + "Uhlu lwezinhlelo zokusebenza zomsebenzi" "Ikhaya" "Susa" "Khipha" @@ -77,19 +81,17 @@ "Izithombe zangemuva" "Izilungiselelo zasekhaya" "Kukhutshazwe umlawuli wakho" - "Ukubuka konke" - "Vumela ukuphendukiswa kwesikrini sasekhaya" - "Uma ifoni iphendukiswa" - "Isilungiselelo sesiboniso samanje asivumeli ukuzungezisa" "Amachashazi esaziso" "Kuvuliwe" "Kuvaliwe" "Ukufinyelela izaziso kuyadingeka" "Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-%1$s" "Shintsha izilungiselelo" + "Bonisa amacashazi esaziso" "Engeza isithonjana eskrinini sasekhaya" "Kwezinhlelo zokusebenza ezintsha" "Shintsha isimo sesithonjana" + "kusikrini sasekhaya" "Sebenzisa okuzenzakalelayo kwesistimu" "Isikwele" "I-Squircle" @@ -119,9 +121,6 @@ "Dala ifolda nge-: %1$s" "Ifolda idaliwe" "Hambisa kusikrini sasekhaya" - "Hambisa isikrini kwesokunxele" - "Hambisa isikrini kwesokudla" - "Isikrini sihanjisiwe" "Shintsha usayizi" "Khuphula ububanzi" "Khuphula ubude" @@ -137,8 +136,9 @@ "Umsebenzi" "Iphrofayela yomsebenzi" "Thola izinhlelo zokusebenza lapha" - - + "Uhlo lokusebenza ngalunye lomsebenzi linebheji futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula." "Kuphethwe inhlangano yakho" "Izaziso nezinhlelo zokusebenza kuvaliwe" + "Vala" + "Kuvaliwe" From 64eb8eafb0bfa6773653b026fdfc2716e258ce35 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 29 Mar 2018 11:43:58 -0700 Subject: [PATCH 25/81] Close all floating views when animating to new screen for newly installed apps. Bug: 64073932 Change-Id: I9253c38391af75ed44a057184144f6a3cee36e69 --- src/com/android/launcher3/Launcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 11e8c5712a..002dd1a9b6 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1976,6 +1976,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L mWorkspace.postDelayed(new Runnable() { public void run() { if (mWorkspace != null) { + AbstractFloatingView.closeAllOpenViews(Launcher.this, false); + mWorkspace.snapToPage(newScreenIndex); mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY); From 3a6746ac04e8564d1e5d244ae855a1ecb1a68105 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 29 Mar 2018 09:39:56 -0700 Subject: [PATCH 26/81] Animate TaskView as you swipe down on it to launch Bug: 73835352 Change-Id: Ia255a7af8fb6cd972f99de6390e097afc29c1b90 --- .../LauncherAppTransitionManagerImpl.java | 106 +++++++++++++----- .../uioverrides/TaskViewTouchController.java | 9 +- .../quickstep/views/LauncherRecentsView.java | 7 +- src/com/android/launcher3/Launcher.java | 4 + .../anim/AnimatorPlaybackController.java | 1 - 5 files changed, 92 insertions(+), 35 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index ab4dae8297..f1471a7d52 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -148,14 +148,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats); - AnimatorSet anim = new AnimatorSet(); - if (anims != null) { - anim.playTogether(anims); - } else { - anim.play(getLauncherAnimators(v, targetCompats)); - anim.play(getWindowAnimators(v, targetCompats)); - } + AnimatorSet anim = createLaunchAnimatorForView(v, targetCompats); mLauncher.getStateManager().setCurrentAnimation(anim); return anim; } @@ -174,6 +167,19 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } + private AnimatorSet createLaunchAnimatorForView(View v, RemoteAnimationTargetCompat[] targets) { + Animator[] anims = composeRecentsLaunchAnimator(v, new AnimConfig(targets, + RECENTS_LAUNCH_DURATION, Interpolators.TOUCH_RESPONSE_INTERPOLATOR)); + AnimatorSet anim = new AnimatorSet(); + if (anims != null) { + anim.playTogether(anims); + } else { + anim.play(getLauncherAnimators(v, targets)); + anim.play(getWindowAnimators(v, targets)); + } + return anim; + } + /** * Try to find a TaskView that corresponds with the component of the launched view. * @@ -232,21 +238,32 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return taskView; } + public AnimatorSet composeUserControlledRecentsLaunchAnimator(TaskView v, AnimConfig config) { + Animator[] anims = composeRecentsLaunchAnimator(v, config); + AnimatorSet anim = new AnimatorSet(); + anim.playTogether(anims); + return anim; + } + /** * Composes the animations for a launch from the recents list if possible. */ - private Animator[] composeRecentsLaunchAnimator(View v, - RemoteAnimationTargetCompat[] targets) { + private Animator[] composeRecentsLaunchAnimator(View v, AnimConfig config) { // Ensure recents is actually visible if (!mLauncher.getStateManager().getState().overviewUi) { return null; } RecentsView recentsView = mLauncher.getOverviewPanel(); - boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); + boolean launcherClosing = launcherIsATargetWithMode(config.targets, MODE_CLOSING); + if (config.userControlled) { + // We don't pass any targets when creating a user-controlled animation. In this case, + // assume launcher is closing. + launcherClosing = true; + } boolean skipLauncherChanges = !launcherClosing; - TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); + TaskView taskView = findTaskViewToLaunch(mLauncher, v, config.targets); if (taskView == null) { return null; } @@ -255,7 +272,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Animator launcherAnim; final AnimatorListenerAdapter windowAnimEndListener; if (launcherClosing) { - launcherAnim = getRecentsLauncherAnimator(recentsView, taskView); + launcherAnim = getRecentsLauncherAnimator(recentsView, taskView, config); // Make sure recents gets fixed up by resetting task alphas and scales, etc. windowAnimEndListener = mReapplyStateListener; } else { @@ -272,8 +289,12 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } - Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets); - windowAnim.addListener(windowAnimEndListener); + Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, config); + if (!config.userControlled) { + // Don't reset properties if the animation is user-controlled, as we will run the + // "real" (not user controlled) animation from where they left off when they let go. + windowAnim.addListener(windowAnimEndListener); + } return new Animator[] {launcherAnim, windowAnim}; } @@ -283,7 +304,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * If launching one of the adjacent tasks, parallax the center task and other adjacent task * to the right. */ - private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v) { + private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v, + AnimConfig config) { AnimatorSet launcherAnimator = new AnimatorSet(); int launchedTaskIndex = recentsView.indexOfChild(v); @@ -307,6 +329,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag .translationY(toTranslationY) .translationX(isRtl ? displacementX : -displacementX) .build()); + adjacentTask1ScaleAndTranslate.setInterpolator(config.interpolator); + adjacentTask1ScaleAndTranslate.setDuration(config.duration); launcherAnimator.play(adjacentTask1ScaleAndTranslate); } if (launchedTaskIndex + 1 < recentsView.getPageCount()) { @@ -318,6 +342,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag .translationY(toTranslationY) .translationX(isRtl ? -displacementX : displacementX) .build()); + adjacentTask2ScaleAndTranslate.setInterpolator(config.interpolator); + adjacentTask2ScaleAndTranslate.setDuration(config.duration); launcherAnimator.play(adjacentTask2ScaleAndTranslate); } } else { @@ -328,6 +354,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag new PropertyListBuilder() .translationX(isRtl ? -displacementX : displacementX) .build()); + centerTaskParallaxOffscreen.setInterpolator(config.interpolator); + centerTaskParallaxOffscreen.setDuration(config.duration); launcherAnimator.play(centerTaskParallaxOffscreen); int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); if (otherAdjacentTaskIndex >= 0 @@ -340,6 +368,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag .translationX(isRtl ? -displacementX : displacementX) .scale(1) .build()); + otherAdjacentTaskParallaxOffscreen.setInterpolator(config.interpolator); + otherAdjacentTaskParallaxOffscreen.setDuration(config.duration); launcherAnimator.play(otherAdjacentTaskParallaxOffscreen); } } @@ -353,6 +383,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen); + allAppsSlideOut.setInterpolator(config.interpolator); + allAppsSlideOut.setDuration(config.duration); launcherAnimator.play(allAppsSlideOut); Workspace workspace = mLauncher.getWorkspace(); @@ -363,12 +395,12 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag .translationX(workspaceScaleAndTranslation[1]) .translationY(workspaceScaleAndTranslation[2]) .build()); + recenterWorkspace.setInterpolator(config.interpolator); + recenterWorkspace.setDuration(config.duration); launcherAnimator.play(recenterWorkspace); CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( workspace.getCurrentPage()); - launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); - launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION); return launcherAnimator; } @@ -392,15 +424,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * animation. */ private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges, - RemoteAnimationTargetCompat[] targets) { + AnimConfig config) { final RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); Rect crop = new Rect(); Matrix matrix = new Matrix(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); - appAnimator.setDuration(RECENTS_LAUNCH_DURATION); - appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); + appAnimator.setDuration(config.duration); + appAnimator.setInterpolator(config.interpolator); appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { boolean isFirstFrame = true; @@ -416,14 +448,17 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag final float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); + float alphaDuration = 75; if (!skipLauncherChanges) { v.setScaleX(tw.taskScale); v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY); - // Defer fading out the view until after the app window gets faded in - v.setAlpha(getValue(1f, 0f, 75, 75, - appAnimator.getDuration() * percent, Interpolators.LINEAR)); + if (!config.userControlled) { + // Defer fading out the view until after the app window gets faded in + v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration, + appAnimator.getDuration() * percent, Interpolators.LINEAR)); + } } matrix.setScale(tw.winScale, tw.winScale); @@ -431,12 +466,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag crop.set(tw.winCrop); // Fade in the app window. - float alphaDuration = 75; float alpha = getValue(0f, 1f, 0, alphaDuration, appAnimator.getDuration() * percent, Interpolators.LINEAR); TransactionCompat t = new TransactionCompat(); - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTargetCompat target : config.targets) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { t.setAlpha(target.leash, alpha); @@ -933,4 +967,24 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag newPercent = i.getInterpolation(newPercent); return end * newPercent + start * (1 - newPercent); } + + public static class AnimConfig { + public RemoteAnimationTargetCompat[] targets; + public long duration; + public Interpolator interpolator; + + public boolean userControlled = false; + + public AnimConfig(RemoteAnimationTargetCompat[] targets, long duration, + Interpolator interpolator) { + this.targets = targets; + this.duration = duration; + this.interpolator = interpolator; + } + + public AnimConfig(long duration, Interpolator interpolator) { + this(new RemoteAnimationTargetCompat[0], duration, interpolator); + userControlled = true; + } + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index d11547de84..dca0018ece 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -28,8 +28,11 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppTransitionManagerImpl; +import com.android.launcher3.LauncherAppTransitionManagerImpl.AnimConfig; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.Interpolators; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; @@ -167,8 +170,10 @@ public class TaskViewTouchController extends AnimatorListenerAdapter .wrap(mPendingAnimation.anim, maxDuration); mEndDisplacement = -mTaskBeingDragged.getHeight(); } else { - AnimatorSet anim = new AnimatorSet(); - // TODO: Setup a zoom animation + LauncherAppTransitionManagerImpl appTransitionManager = + (LauncherAppTransitionManagerImpl) mLauncher.getAppTransitionManager(); + AnimatorSet anim = appTransitionManager.composeUserControlledRecentsLaunchAnimator( + mTaskBeingDragged, new AnimConfig(maxDuration, Interpolators.ZOOM_IN)); mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration); mTempCords[1] = mTaskBeingDragged.getHeight(); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 55ed9a941e..ad0e2530c2 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -26,7 +26,6 @@ import android.util.AttributeSet; import android.util.FloatProperty; import android.view.View; import android.view.ViewDebug; -import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; @@ -92,11 +91,7 @@ public class LauncherRecentsView extends RecentsView implements Insett mInsets.set(insets); DeviceProfile dp = mActivity.getDeviceProfile(); Rect padding = getPadding(dp, getContext()); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - lp.bottomMargin = padding.bottom; - setLayoutParams(lp); - - setPadding(padding.left, padding.top, padding.right, 0); + setPadding(padding.left, padding.top, padding.right, padding.bottom); mPagePadding.set(padding); mPagePadding.top += getResources().getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 11e8c5712a..50a88ce9ed 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1684,6 +1684,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L : mAppTransitionManager.getActivityLaunchOptions(this, v); } + public LauncherAppTransitionManager getAppTransitionManager() { + return mAppTransitionManager; + } + @TargetApi(Build.VERSION_CODES.M) @Override protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) { diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java index 68e98479b0..6fea201564 100644 --- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java +++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java @@ -206,7 +206,6 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat anim.setCurrentPlayTime(Math.min(playPos, anim.getDuration())); } } - } private class OnAnimationEndDispatcher extends AnimationSuccessListener { From 76e2775bb638757216fcaa96f8a62654fb56b19a Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 29 Mar 2018 21:25:32 -0700 Subject: [PATCH 27/81] Moving some methods related to task launch animation to recents view and related classes. This allows the common animation to be used in fallback activity. Bug: 75979063 Change-Id: I2b5bf5e66406621305b9a076793434f9c5cecdfd --- .../LauncherAppTransitionManagerImpl.java | 219 +++--------------- .../uioverrides/TaskViewTouchController.java | 17 +- .../quickstep/views/LauncherRecentsView.java | 26 +++ .../android/quickstep/views/RecentsView.java | 93 ++++++++ .../com/android/quickstep/views/TaskView.java | 20 ++ .../anim/AnimatorPlaybackController.java | 5 + 6 files changed, 178 insertions(+), 202 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index f1471a7d52..8f2e104dab 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -17,7 +17,6 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; @@ -53,7 +52,6 @@ import com.android.launcher3.InsettableFrameLayout.LayoutParams; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.shortcuts.DeepShortcutView; @@ -93,8 +91,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final int CLOSING_TRANSITION_DURATION_MS = 350; // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down. - private static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f; - private static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f; + public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f; + public static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f; private final DragLayer mDragLayer; private final Launcher mLauncher; @@ -148,7 +146,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - AnimatorSet anim = createLaunchAnimatorForView(v, targetCompats); + Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats); + AnimatorSet anim = new AnimatorSet(); + if (anims != null) { + anim.playTogether(anims); + } else { + anim.play(getLauncherAnimators(v, targetCompats)); + anim.play(getWindowAnimators(v, targetCompats)); + } mLauncher.getStateManager().setCurrentAnimation(anim); return anim; } @@ -167,19 +172,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } - private AnimatorSet createLaunchAnimatorForView(View v, RemoteAnimationTargetCompat[] targets) { - Animator[] anims = composeRecentsLaunchAnimator(v, new AnimConfig(targets, - RECENTS_LAUNCH_DURATION, Interpolators.TOUCH_RESPONSE_INTERPOLATOR)); - AnimatorSet anim = new AnimatorSet(); - if (anims != null) { - anim.playTogether(anims); - } else { - anim.play(getLauncherAnimators(v, targets)); - anim.play(getWindowAnimators(v, targets)); - } - return anim; - } - /** * Try to find a TaskView that corresponds with the component of the launched view. * @@ -238,32 +230,21 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return taskView; } - public AnimatorSet composeUserControlledRecentsLaunchAnimator(TaskView v, AnimConfig config) { - Animator[] anims = composeRecentsLaunchAnimator(v, config); - AnimatorSet anim = new AnimatorSet(); - anim.playTogether(anims); - return anim; - } - /** * Composes the animations for a launch from the recents list if possible. */ - private Animator[] composeRecentsLaunchAnimator(View v, AnimConfig config) { + private Animator[] composeRecentsLaunchAnimator(View v, + RemoteAnimationTargetCompat[] targets) { // Ensure recents is actually visible if (!mLauncher.getStateManager().getState().overviewUi) { return null; } RecentsView recentsView = mLauncher.getOverviewPanel(); - boolean launcherClosing = launcherIsATargetWithMode(config.targets, MODE_CLOSING); - if (config.userControlled) { - // We don't pass any targets when creating a user-controlled animation. In this case, - // assume launcher is closing. - launcherClosing = true; - } + boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); boolean skipLauncherChanges = !launcherClosing; - TaskView taskView = findTaskViewToLaunch(mLauncher, v, config.targets); + TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); if (taskView == null) { return null; } @@ -272,7 +253,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Animator launcherAnim; final AnimatorListenerAdapter windowAnimEndListener; if (launcherClosing) { - launcherAnim = getRecentsLauncherAnimator(recentsView, taskView, config); + launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView); + launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); + launcherAnim.setDuration(RECENTS_LAUNCH_DURATION); + // Make sure recents gets fixed up by resetting task alphas and scales, etc. windowAnimEndListener = mReapplyStateListener; } else { @@ -289,150 +273,25 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } - Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, config); - if (!config.userControlled) { - // Don't reset properties if the animation is user-controlled, as we will run the - // "real" (not user controlled) animation from where they left off when they let go. - windowAnim.addListener(windowAnimEndListener); - } + Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets); + windowAnim.addListener(windowAnimEndListener); return new Animator[] {launcherAnim, windowAnim}; } - /** - * Animate adjacent tasks off screen while scaling up, and translate hotseat off screen as well. - * - * If launching one of the adjacent tasks, parallax the center task and other adjacent task - * to the right. - */ - private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v, - AnimConfig config) { - AnimatorSet launcherAnimator = new AnimatorSet(); - - int launchedTaskIndex = recentsView.indexOfChild(v); - int centerTaskIndex = recentsView.getCurrentPage(); - boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex; - boolean isRtl = recentsView.isRtl(); - - RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); - TaskWindowBounds endInterpolation = recentsInterpolator.interpolate(1); - float toScale = endInterpolation.taskScale; - float toTranslationY = endInterpolation.taskY; - float displacementX = v.getWidth() * (toScale - v.getScaleX()); - if (launchingCenterTask) { - - if (launchedTaskIndex - 1 >= 0) { - TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1); - ObjectAnimator adjacentTask1ScaleAndTranslate = - LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1, - new PropertyListBuilder() - .scale(adjacentPage1.getScaleX() * toScale) - .translationY(toTranslationY) - .translationX(isRtl ? displacementX : -displacementX) - .build()); - adjacentTask1ScaleAndTranslate.setInterpolator(config.interpolator); - adjacentTask1ScaleAndTranslate.setDuration(config.duration); - launcherAnimator.play(adjacentTask1ScaleAndTranslate); - } - if (launchedTaskIndex + 1 < recentsView.getPageCount()) { - TaskView adjacentTask2 = (TaskView) recentsView.getPageAt(launchedTaskIndex + 1); - ObjectAnimator adjacentTask2ScaleAndTranslate = - LauncherAnimUtils.ofPropertyValuesHolder(adjacentTask2, - new PropertyListBuilder() - .scale(adjacentTask2.getScaleX() * toScale) - .translationY(toTranslationY) - .translationX(isRtl ? -displacementX : displacementX) - .build()); - adjacentTask2ScaleAndTranslate.setInterpolator(config.interpolator); - adjacentTask2ScaleAndTranslate.setDuration(config.duration); - launcherAnimator.play(adjacentTask2ScaleAndTranslate); - } - } else { - // We are launching an adjacent task, so parallax the center and other adjacent task. - TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex); - ObjectAnimator centerTaskParallaxOffscreen = - LauncherAnimUtils.ofPropertyValuesHolder(centerTask, - new PropertyListBuilder() - .translationX(isRtl ? -displacementX : displacementX) - .build()); - centerTaskParallaxOffscreen.setInterpolator(config.interpolator); - centerTaskParallaxOffscreen.setDuration(config.duration); - launcherAnimator.play(centerTaskParallaxOffscreen); - int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); - if (otherAdjacentTaskIndex >= 0 - && otherAdjacentTaskIndex < recentsView.getPageCount()) { - TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt( - otherAdjacentTaskIndex); - ObjectAnimator otherAdjacentTaskParallaxOffscreen = - LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, - new PropertyListBuilder() - .translationX(isRtl ? -displacementX : displacementX) - .scale(1) - .build()); - otherAdjacentTaskParallaxOffscreen.setInterpolator(config.interpolator); - otherAdjacentTaskParallaxOffscreen.setDuration(config.duration); - launcherAnimator.play(otherAdjacentTaskParallaxOffscreen); - } - } - - float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN; - LauncherState state = mLauncher.getStateManager().getState(); - if ((state.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) != 0) { - float maxShiftRange = mDeviceProfile.heightPx; - float currShiftRange = mLauncher.getAllAppsController().getShiftRange(); - allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange; - } - Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(), - ALL_APPS_PROGRESS, allAppsProgressOffscreen); - allAppsSlideOut.setInterpolator(config.interpolator); - allAppsSlideOut.setDuration(config.duration); - launcherAnimator.play(allAppsSlideOut); - - Workspace workspace = mLauncher.getWorkspace(); - float[] workspaceScaleAndTranslation = NORMAL - .getWorkspaceScaleAndTranslation(mLauncher); - Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder( - workspace, new PropertyListBuilder() - .translationX(workspaceScaleAndTranslation[1]) - .translationY(workspaceScaleAndTranslation[2]) - .build()); - recenterWorkspace.setInterpolator(config.interpolator); - recenterWorkspace.setDuration(config.duration); - launcherAnimator.play(recenterWorkspace); - CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( - workspace.getCurrentPage()); - - return launcherAnimator; - } - - private RecentsAnimationInterpolator getRecentsInterpolator(TaskView v) { - Rect taskViewBounds = new Rect(); - mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); - - // TODO: Use the actual target insets instead of the current thumbnail insets in case the - // device state has changed - return new RecentsAnimationInterpolator( - new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), - v.getThumbnail().getInsets(), - taskViewBounds, - new Rect(0, v.getThumbnail().getTop(), 0, 0), - v.getScaleX(), - v.getTranslationX()); - } - /** * @return Animator that controls the window of the opening targets for the recents launch * animation. */ private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges, - AnimConfig config) { - final RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); + RemoteAnimationTargetCompat[] targets) { + final RecentsAnimationInterpolator recentsInterpolator = v.getRecentsInterpolator(); Rect crop = new Rect(); Matrix matrix = new Matrix(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); - appAnimator.setDuration(config.duration); - appAnimator.setInterpolator(config.interpolator); + appAnimator.setDuration(RECENTS_LAUNCH_DURATION); + appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { boolean isFirstFrame = true; @@ -454,11 +313,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY); - if (!config.userControlled) { - // Defer fading out the view until after the app window gets faded in - v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration, - appAnimator.getDuration() * percent, Interpolators.LINEAR)); - } + // Defer fading out the view until after the app window gets faded in + v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration, + appAnimator.getDuration() * percent, Interpolators.LINEAR)); } matrix.setScale(tw.winScale, tw.winScale); @@ -470,7 +327,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag appAnimator.getDuration() * percent, Interpolators.LINEAR); TransactionCompat t = new TransactionCompat(); - for (RemoteAnimationTargetCompat target : config.targets) { + for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { t.setAlpha(target.leash, alpha); @@ -967,24 +824,4 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag newPercent = i.getInterpolation(newPercent); return end * newPercent + start * (1 - newPercent); } - - public static class AnimConfig { - public RemoteAnimationTargetCompat[] targets; - public long duration; - public Interpolator interpolator; - - public boolean userControlled = false; - - public AnimConfig(RemoteAnimationTargetCompat[] targets, long duration, - Interpolator interpolator) { - this.targets = targets; - this.duration = duration; - this.interpolator = interpolator; - } - - public AnimConfig(long duration, Interpolator interpolator) { - this(new RemoteAnimationTargetCompat[0], duration, interpolator); - userControlled = true; - } - } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index dca0018ece..369ae3ab6c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -20,7 +20,6 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.util.Log; import android.view.MotionEvent; @@ -28,8 +27,6 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppTransitionManagerImpl; -import com.android.launcher3.LauncherAppTransitionManagerImpl.AnimConfig; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; @@ -166,21 +163,20 @@ public class TaskViewTouchController extends AnimatorListenerAdapter if (goingUp) { mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged, true /* animateTaskView */, true /* removeTask */, maxDuration); - mCurrentAnimation = AnimatorPlaybackController - .wrap(mPendingAnimation.anim, maxDuration); + mEndDisplacement = -mTaskBeingDragged.getHeight(); } else { - LauncherAppTransitionManagerImpl appTransitionManager = - (LauncherAppTransitionManagerImpl) mLauncher.getAppTransitionManager(); - AnimatorSet anim = appTransitionManager.composeUserControlledRecentsLaunchAnimator( - mTaskBeingDragged, new AnimConfig(maxDuration, Interpolators.ZOOM_IN)); - mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration); + mPendingAnimation = mRecentsView.createTaskLauncherAnimation( + mTaskBeingDragged, maxDuration); + mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN); mTempCords[1] = mTaskBeingDragged.getHeight(); dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords); mEndDisplacement = dl.getHeight() - mTempCords[1]; } + mCurrentAnimation = AnimatorPlaybackController + .wrap(mPendingAnimation.anim, maxDuration); mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.dispatchOnStart(); mProgressMultiplier = 1 / mEndDisplacement; @@ -258,7 +254,6 @@ public class TaskViewTouchController extends AnimatorListenerAdapter } if (wasSuccess) { if (!mCurrentAnimationIsGoingUp) { - mTaskBeingDragged.launchTask(false); mLauncher.getUserEventDispatcher().logTaskLaunch(logAction, Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index ad0e2530c2..d428f23dac 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -15,8 +15,14 @@ */ package com.android.quickstep.views; +import static com.android.launcher3.LauncherAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN; +import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; @@ -30,6 +36,7 @@ import android.view.ViewDebug; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; import com.android.launcher3.R; /** @@ -137,4 +144,23 @@ public class LauncherRecentsView extends RecentsView implements Insett // Lazily update the empty message only when the task stack is reapplied updateEmptyMessage(); } + + /** + * Animates adjacent tasks and translate hotseat off screen as well. + */ + @Override + public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) { + AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv); + + float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN; + LauncherState state = mActivity.getStateManager().getState(); + if ((state.getVisibleElements(mActivity) & ALL_APPS_HEADER_EXTRA) != 0) { + float maxShiftRange = mActivity.getDeviceProfile().heightPx; + float currShiftRange = mActivity.getAllAppsController().getShiftRange(); + allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange; + } + anim.play(ObjectAnimator.ofFloat( + mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen)); + return anim; + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7a5fd2f0fb..bac8fc7461 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -55,10 +55,13 @@ import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Themes; import com.android.quickstep.PendingAnimation; import com.android.quickstep.QuickScrubController; +import com.android.quickstep.RecentsAnimationInterpolator; +import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsModel; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoader; @@ -839,4 +842,94 @@ public abstract class RecentsView canvas.restore(); } } + + /** + * Animate adjacent tasks off screen while scaling up. + * + * If launching one of the adjacent tasks, parallax the center task and other adjacent task + * to the right. + */ + public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) { + AnimatorSet anim = new AnimatorSet(); + + int taskIndex = indexOfChild(tv); + int centerTaskIndex = getCurrentPage(); + boolean launchingCenterTask = taskIndex == centerTaskIndex; + + TaskWindowBounds endInterpolation = tv.getRecentsInterpolator().interpolate(1); + float toScale = endInterpolation.taskScale; + float toTranslationY = endInterpolation.taskY; + + float displacementX = tv.getWidth() * (toScale - tv.getScaleX()); + if (launchingCenterTask) { + if (taskIndex - 1 >= 0) { + anim.play(createAnimForChild( + taskIndex - 1, toScale, displacementX, toTranslationY)); + } + if (taskIndex + 1 < getPageCount()) { + anim.play(createAnimForChild( + taskIndex + 1, toScale, -displacementX, toTranslationY)); + } + } else { + // We are launching an adjacent task, so parallax the center and other adjacent task. + anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), TRANSLATION_X, + mIsRtl ? -displacementX : displacementX)); + + int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex); + if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) { + anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex), + new PropertyListBuilder() + .translationX(mIsRtl ? -displacementX : displacementX) + .scale(1) + .build())); + } + } + return anim; + } + + private ObjectAnimator createAnimForChild(int childIndex, float toScale, float tx, float ty) { + View child = getChildAt(childIndex); + return ObjectAnimator.ofPropertyValuesHolder(child, + new PropertyListBuilder() + .scale(child.getScaleX() * toScale) + .translationY(ty) + .translationX(mIsRtl ? tx : -tx) + .build()); + } + + public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) { + if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) { + throw new IllegalStateException("Another pending animation is still running"); + } + AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv); + + int count = getChildCount(); + if (count == 0) { + return new PendingAnimation(anim); + } + + final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator(); + ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1); + targetViewAnim.addUpdateListener((animation) -> { + float percent = animation.getAnimatedFraction(); + TaskWindowBounds tw = recentsInterpolator.interpolate(percent); + tv.setScaleX(tw.taskScale); + tv.setScaleY(tw.taskScale); + tv.setTranslationX(tw.taskX); + tv.setTranslationY(tw.taskY); + }); + anim.play(targetViewAnim); + anim.setDuration(duration); + + mPendingAnimation = new PendingAnimation(anim); + mPendingAnimation.addEndListener((isSuccess) -> { + if (isSuccess) { + tv.launchTask(false); + } else { + resetTaskVisuals(); + } + mPendingAnimation = null; + }); + return mPendingAnimation; + } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 9884a4858f..a701862a82 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -21,6 +21,7 @@ import android.app.ActivityOptions; import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; +import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.view.View; @@ -29,7 +30,9 @@ import android.widget.FrameLayout; import android.widget.ImageView; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; import com.android.systemui.shared.recents.model.Task; @@ -183,6 +186,23 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback return false; } + public RecentsAnimationInterpolator getRecentsInterpolator() { + Rect taskViewBounds = new Rect(); + BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext()); + DeviceProfile dp = activity.getDeviceProfile(); + activity.getDragLayer().getDescendantRectRelativeToSelf(this, taskViewBounds); + + // TODO: Use the actual target insets instead of the current thumbnail insets in case the + // device state has changed + return new RecentsAnimationInterpolator( + new Rect(0, 0, dp.widthPx, dp.heightPx), + getThumbnail().getInsets(), + taskViewBounds, + new Rect(0, getThumbnail().getTop(), 0, 0), + getScaleX(), + getTranslationX()); + } + private static final class TaskOutlineProvider extends ViewOutlineProvider { private final int mMarginTop; diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java index 6fea201564..087752df1e 100644 --- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java +++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java @@ -18,6 +18,7 @@ package com.android.launcher3.anim; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; +import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import java.util.ArrayList; @@ -184,10 +185,14 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat private void getAnimationsRecur(AnimatorSet anim, ArrayList out) { long forceDuration = anim.getDuration(); + TimeInterpolator forceInterpolator = anim.getInterpolator(); for (Animator child : anim.getChildAnimations()) { if (forceDuration > 0) { child.setDuration(forceDuration); } + if (forceInterpolator != null) { + child.setInterpolator(forceInterpolator); + } if (child instanceof ValueAnimator) { out.add((ValueAnimator) child); } else if (child instanceof AnimatorSet) { From ab83773e211daf43b6b3ab327be2e94bf61663b3 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Mar 2018 17:35:54 -0700 Subject: [PATCH 28/81] Updating fallback activity > Wallpaper based theme support > Light/dark system UI > Swipe gestures to start and dismiss a task > Fixing insets and task preview size Bug: 75979063 Change-Id: Id402e6ac50551a7c0849742e3a0e77df3ead5aa2 --- quickstep/AndroidManifest.xml | 11 +++++- .../res/layout/fallback_recents_activity.xml | 9 +++-- .../uioverrides/TaskViewTouchController.java | 34 ++++++++--------- .../launcher3/uioverrides/UiFactory.java | 19 ++++++++-- .../quickstep/ActivityControlHelper.java | 1 + .../quickstep/FallbackActivityOptions.java | 15 +++++++- .../android/quickstep/RecentsActivity.java | 8 ++++ .../{ => fallback}/FallbackRecentsView.java | 10 ++--- .../{ => fallback}/RecentsRootView.java | 15 ++++++-- .../fallback/RecentsTaskController.java | 31 +++++++++++++++ .../android/quickstep/views/RecentsView.java | 2 +- .../launcher3/BaseDraggingActivity.java | 38 ++++++++++++++++++- src/com/android/launcher3/Launcher.java | 22 +---------- .../dynamicui/WallpaperColorInfo.java | 33 ++++++---------- 14 files changed, 168 insertions(+), 80 deletions(-) rename quickstep/src/com/android/quickstep/{ => fallback}/FallbackRecentsView.java (88%) rename quickstep/src/com/android/quickstep/{ => fallback}/RecentsRootView.java (79%) create mode 100644 quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 8b28597dd1..f62d1d6ed5 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -48,7 +48,16 @@ It is set to true so that the activity can be started from command line --> + android:excludeFromRecents="true" + android:launchMode="singleTask" + android:clearTaskOnLaunch="true" + android:stateNotNeeded="true" + android:theme="@style/LauncherTheme" + android:screenOrientation="unspecified" + android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout|smallestScreenSize" + android:resizeableActivity="true" + android:resumeWhilePausing="true" + android:taskAffinity="" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true"> - - \ No newline at end of file + \ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index 369ae3ab6c..7b2487ada8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.uioverrides; -import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import android.animation.Animator; @@ -26,15 +25,15 @@ import android.view.MotionEvent; import android.view.View; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.Launcher; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.TouchController; +import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.PendingAnimation; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -42,8 +41,8 @@ import com.android.quickstep.views.TaskView; /** * Touch controller for handling task view card swipes */ -public class TaskViewTouchController extends AnimatorListenerAdapter - implements TouchController, SwipeDetector.Listener { +public abstract class TaskViewTouchController + extends AnimatorListenerAdapter implements TouchController, SwipeDetector.Listener { private static final String TAG = "OverviewSwipeController"; @@ -53,7 +52,7 @@ public class TaskViewTouchController extends AnimatorListenerAdapter // Progress after which the transition is assumed to be a success in case user does not fling private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f; - private final Launcher mLauncher; + protected final T mActivity; private final SwipeDetector mDetector; private final RecentsView mRecentsView; private final int[] mTempCords = new int[2]; @@ -70,10 +69,10 @@ public class TaskViewTouchController extends AnimatorListenerAdapter private TaskView mTaskBeingDragged; - public TaskViewTouchController(Launcher launcher) { - mLauncher = launcher; - mRecentsView = launcher.getOverviewPanel(); - mDetector = new SwipeDetector(launcher, this, SwipeDetector.VERTICAL); + public TaskViewTouchController(T activity) { + mActivity = activity; + mRecentsView = activity.getOverviewPanel(); + mDetector = new SwipeDetector(activity, this, SwipeDetector.VERTICAL); } private boolean canInterceptTouch() { @@ -81,12 +80,14 @@ public class TaskViewTouchController extends AnimatorListenerAdapter // If we are already animating from a previous state, we can intercept. return true; } - if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { + if (AbstractFloatingView.getTopOpenView(mActivity) != null) { return false; } - return mLauncher.isInState(OVERVIEW); + return isRecentsInteractive(); } + protected abstract boolean isRecentsInteractive(); + @Override public void onAnimationCancel(Animator animation) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { @@ -115,7 +116,7 @@ public class TaskViewTouchController extends AnimatorListenerAdapter mTaskBeingDragged = null; View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage()); - if (view instanceof TaskView && mLauncher.getDragLayer().isEventOverView(view, ev)) { + if (view instanceof TaskView && mActivity.getDragLayer().isEventOverView(view, ev)) { // The tile can be dragged down to open the task. mTaskBeingDragged = (TaskView) view; directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH; @@ -156,9 +157,8 @@ public class TaskViewTouchController extends AnimatorListenerAdapter } mCurrentAnimationIsGoingUp = goingUp; - float range = mLauncher.getAllAppsController().getShiftRange(); - long maxDuration = (long) (2 * range); - DragLayer dl = mLauncher.getDragLayer(); + BaseDragLayer dl = mActivity.getDragLayer(); + long maxDuration = (long) (2 * dl.getHeight()); if (goingUp) { mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged, @@ -254,7 +254,7 @@ public class TaskViewTouchController extends AnimatorListenerAdapter } if (wasSuccess) { if (!mCurrentAnimationIsGoingUp) { - mLauncher.getUserEventDispatcher().logTaskLaunch(logAction, + mActivity.getUserEventDispatcher().logTaskLaunch(logAction, Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index e6d06da5e7..3cae3718f3 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -16,6 +16,7 @@ package com.android.launcher3.uioverrides; +import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.Utilities.getPrefs; import static com.android.quickstep.OverviewInteractionState.KEY_SWIPE_UP_ENABLED; import static com.android.launcher3.LauncherState.ALL_APPS; @@ -41,19 +42,19 @@ public class UiFactory { return new TouchController[] { launcher.getDragController(), new LandscapeStatesTouchController(launcher), - new TaskViewTouchController(launcher)}; + new LauncherTaskViewcontroller(launcher)}; } if (launcher.getDeviceProfile().isVerticalBarLayout()) { return new TouchController[] { launcher.getDragController(), new LandscapeStatesTouchController(launcher), new LandscapeEdgeSwipeController(launcher), - new TaskViewTouchController(launcher)}; + new LauncherTaskViewcontroller(launcher)}; } else { return new TouchController[] { launcher.getDragController(), new PortraitStatesTouchController(launcher), - new TaskViewTouchController(launcher)}; + new LauncherTaskViewcontroller(launcher)}; } } @@ -101,4 +102,16 @@ public class UiFactory { model.onTrimMemory(level); } } + + private static class LauncherTaskViewcontroller extends TaskViewTouchController { + + public LauncherTaskViewcontroller(Launcher activity) { + super(activity); + } + + @Override + protected boolean isRecentsInteractive() { + return mActivity.isInState(OVERVIEW); + } + } } diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 9e2e5acf5f..4e3528c84d 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -41,6 +41,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.ViewOnDrawExecutor; +import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.views.LauncherLayoutListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java index 3a7fb2db6d..04352c390b 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java @@ -16,13 +16,13 @@ package com.android.quickstep; import android.graphics.Rect; -import android.util.Log; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RecentsAnimationListener; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; /** @@ -39,6 +39,7 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat { @Override public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) { + showOpeningTarget(targetCompats); DummyRecentsAnimationControllerCompat dummyRecentsAnim = new DummyRecentsAnimationControllerCompat(runnable); @@ -52,6 +53,18 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat { mListener.onAnimationCanceled(); } + private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) { + for (RemoteAnimationTargetCompat target : targetCompats) { + TransactionCompat t = new TransactionCompat(); + int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING + ? Integer.MAX_VALUE + : target.prefixOrderIndex; + t.setLayer(target.leash, layer); + t.show(target.leash); + t.apply(); + } + } + private static class DummyRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat { diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index e5792056aa..cf60fdff65 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -26,7 +26,11 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.uioverrides.UiFactory; +import com.android.launcher3.util.SystemUiController; +import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; +import com.android.quickstep.fallback.FallbackRecentsView; +import com.android.quickstep.fallback.RecentsRootView; /** * A simple activity to show the recently launched tasks @@ -51,6 +55,10 @@ public class RecentsActivity extends BaseDraggingActivity { mRecentsRootView = findViewById(R.id.drag_layer); mFallbackRecentsView = findViewById(R.id.overview_panel); + mRecentsRootView.setup(); + + getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, + Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); RecentsActivityTracker.onRecentsActivityCreate(this); } diff --git a/quickstep/src/com/android/quickstep/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java similarity index 88% rename from quickstep/src/com/android/quickstep/FallbackRecentsView.java rename to quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index 251e958063..7d7f88fdb2 100644 --- a/quickstep/src/com/android/quickstep/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep; +package com.android.quickstep.fallback; import android.content.Context; import android.graphics.Canvas; @@ -23,6 +23,7 @@ import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; +import com.android.quickstep.RecentsActivity; import com.android.quickstep.views.RecentsView; public class FallbackRecentsView extends RecentsView implements Insettable { @@ -73,12 +74,7 @@ public class FallbackRecentsView extends RecentsView implements public static void getCenterPageRect(DeviceProfile grid, Context context, Rect outRect) { Rect targetPadding = getPadding(grid, context); verticalCenter(targetPadding, grid); - Rect insets = grid.getInsets(); - outRect.set( - targetPadding.left + insets.left, - targetPadding.top + insets.top, - grid.widthPx - targetPadding.right - insets.right, - grid.heightPx - targetPadding.bottom - insets.bottom); + getPageRect(grid, context, outRect, targetPadding); } @Override diff --git a/quickstep/src/com/android/quickstep/RecentsRootView.java b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java similarity index 79% rename from quickstep/src/com/android/quickstep/RecentsRootView.java rename to quickstep/src/com/android/quickstep/fallback/RecentsRootView.java index 24785f9316..7aaa88c38d 100644 --- a/quickstep/src/com/android/quickstep/RecentsRootView.java +++ b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep; +package com.android.quickstep.fallback; import android.annotation.TargetApi; import android.content.Context; @@ -25,15 +25,22 @@ import com.android.launcher3.R; import com.android.launcher3.util.Themes; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; +import com.android.quickstep.RecentsActivity; public class RecentsRootView extends BaseDragLayer { - private final BaseActivity mActivity; + private final RecentsActivity mActivity; public RecentsRootView(Context context, AttributeSet attrs) { super(context, attrs); - mActivity = BaseActivity.fromContext(context); - mControllers = new TouchController[0]; + mActivity = (RecentsActivity) BaseActivity.fromContext(context); + setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | SYSTEM_UI_FLAG_LAYOUT_STABLE); + } + + public void setup() { + mControllers = new TouchController[] { new RecentsTaskController(mActivity) }; } @TargetApi(23) diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java new file mode 100644 index 0000000000..9463cc90f1 --- /dev/null +++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 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.fallback; + +import com.android.launcher3.uioverrides.TaskViewTouchController; +import com.android.quickstep.RecentsActivity; + +public class RecentsTaskController extends TaskViewTouchController { + + public RecentsTaskController(RecentsActivity activity) { + super(activity); + } + + @Override + protected boolean isRecentsInteractive() { + return mActivity.hasWindowFocus(); + } +} diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index bac8fc7461..1c4e5111ac 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -405,7 +405,7 @@ public abstract class RecentsView getPageRect(grid, context, outRect, targetPadding); } - private static void getPageRect(DeviceProfile grid, Context context, Rect outRect, + protected static void getPageRect(DeviceProfile grid, Context context, Rect outRect, Rect targetPadding) { Rect insets = grid.getInsets(); outRect.set( diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 34819afe43..4c11fe66e0 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -34,13 +34,15 @@ import android.widget.Toast; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.dynamicui.WallpaperColorInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.views.BaseDragLayer; /** * Extension of BaseActivity allowing support for drag-n-drop */ -public abstract class BaseDraggingActivity extends BaseActivity { +public abstract class BaseDraggingActivity extends BaseActivity + implements WallpaperColorInfo.OnChangeListener { private static final String TAG = "BaseDraggingActivity"; @@ -57,10 +59,38 @@ public abstract class BaseDraggingActivity extends BaseActivity { private OnStartCallback mOnStartCallback; + private int mThemeRes = R.style.LauncherTheme; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mIsSafeModeEnabled = getPackageManager().isSafeMode(); + + // Update theme + WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this); + wallpaperColorInfo.addOnChangeListener(this); + int themeRes = getThemeRes(wallpaperColorInfo); + if (themeRes != mThemeRes) { + mThemeRes = themeRes; + setTheme(themeRes); + } + } + + @Override + public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) { + if (mThemeRes != getThemeRes(wallpaperColorInfo)) { + recreate(); + } + } + + protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) { + if (wallpaperColorInfo.isDark()) { + return R.style.LauncherThemeDark; + } else if (wallpaperColorInfo.supportsDarkText()) { + return R.style.LauncherThemeDarkText; + } else { + return R.style.LauncherTheme; + } } @Override @@ -203,6 +233,12 @@ public abstract class BaseDraggingActivity extends BaseActivity { } } + @Override + protected void onDestroy() { + super.onDestroy(); + WallpaperColorInfo.getInstance(this).removeOnChangeListener(this); + } + public void setOnStartCallback(OnStartCallback callback) { mOnStartCallback = callback; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 056404e7a4..e2f748837c 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -135,8 +135,8 @@ import java.util.Set; /** * Default launcher application. */ -public class Launcher extends BaseDraggingActivity implements LauncherExterns, LauncherModel.Callbacks, - LauncherProviderChangeListener, WallpaperColorInfo.OnThemeChangeListener { +public class Launcher extends BaseDraggingActivity + implements LauncherExterns, LauncherModel.Callbacks, LauncherProviderChangeListener { public static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -266,10 +266,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L } TraceHelper.beginSection("Launcher-onCreate"); - WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this); - wallpaperColorInfo.setOnThemeChangeListener(this); - overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText()); - super.onCreate(savedInstanceState); TraceHelper.partitionSection("Launcher-onCreate", "super call"); @@ -402,23 +398,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L return mRotationHelper; } - @Override - public void onThemeChanged() { - recreate(); - } - public LauncherStateManager getStateManager() { return mStateManager; } - protected void overrideTheme(boolean isDark, boolean supportsDarkText) { - if (isDark) { - setTheme(R.style.LauncherThemeDark); - } else if (supportsDarkText) { - setTheme(R.style.LauncherThemeDarkText); - } - } - @Override public T findViewById(int id) { return mLauncherView.findViewById(id); @@ -1367,7 +1350,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L } TextKeyListener.getInstance().release(); - WallpaperColorInfo.getInstance(this).setOnThemeChangeListener(null); LauncherAnimUtils.onDestroyActivity(); diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java index 267e9301a7..32605a2ebe 100644 --- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java +++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java @@ -33,7 +33,8 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange private int mSecondaryColor; private boolean mIsDark; private boolean mSupportsDarkText; - private OnThemeChangeListener mOnThemeChangeListener; + + private OnChangeListener[] mTempListeners; private WallpaperColorInfo(Context context) { mWallpaperManager = WallpaperManagerCompat.getInstance(context); @@ -61,10 +62,8 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange @Override public void onColorsChanged(WallpaperColorsCompat colors, int which) { if ((which & FLAG_SYSTEM) != 0) { - boolean wasDarkTheme = mIsDark; - boolean didSupportDarkText = mSupportsDarkText; update(colors); - notifyChange(wasDarkTheme != mIsDark || didSupportDarkText != mSupportsDarkText); + notifyChange(); } } @@ -85,10 +84,6 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false; } - public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) { - this.mOnThemeChangeListener = onThemeChangeListener; - } - public void addOnChangeListener(OnChangeListener listener) { mListeners.add(listener); } @@ -97,23 +92,19 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange mListeners.remove(listener); } - public void notifyChange(boolean themeChanged) { - if (themeChanged) { - if (mOnThemeChangeListener != null) { - mOnThemeChangeListener.onThemeChanged(); - } - } else { - for (OnChangeListener listener : mListeners) { - listener.onExtractedColorsChanged(this); - } + private void notifyChange() { + OnChangeListener[] copy = + mTempListeners != null && mTempListeners.length == mListeners.size() ? + mTempListeners : new OnChangeListener[mListeners.size()]; + + // Create a new array to avoid concurrent modification when the activity destroys itself. + mTempListeners = mListeners.toArray(copy); + for (OnChangeListener listener : mTempListeners) { + listener.onExtractedColorsChanged(this); } } public interface OnChangeListener { void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo); } - - public interface OnThemeChangeListener { - void onThemeChanged(); - } } From 41e7328cb5c32bba713f88296cb0fa5e618274b1 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 30 Mar 2018 10:34:23 -0700 Subject: [PATCH 29/81] Fixing LauncherState not getting applied in some cases > In case of swipe-up from homescreen, super method was not called everytime > When swiping up from an app, repply() state was skipping as we didn't finish the last animation, leading to views staying visible and interactive > Intercepting touch in RecentsView and pagesView based on visibility Bug: 76467534 Change-Id: Ia5ef58d508b656f371a32cd2f1de00dd18c6aa5c --- .../uioverrides/PortraitStatesTouchController.java | 14 +++++++++----- .../quickstep/WindowTransformSwipeHandler.java | 4 ++++ .../com/android/quickstep/views/RecentsView.java | 8 ++++++++ .../launcher3/ShortcutAndWidgetContainer.java | 12 ++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index 1e006e5752..7d9cce49a2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -207,6 +207,14 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr @Override protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration, LauncherState targetState, float velocity, boolean isFling) { + handleFirstSwipeToOverview(animator, expectedDuration, targetState, velocity, isFling); + super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState, + velocity, isFling); + } + + private void handleFirstSwipeToOverview(final ValueAnimator animator, + final long expectedDuration, final LauncherState targetState, final float velocity, + final boolean isFling) { if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) { mFinishFastOnSecondTouch = true; @@ -220,7 +228,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr // TODO: Clean up these magic calculations // Linearly interpolate the max value based on the velocity. float maxValue = Math.max(absVelocity > 4 ? 1 + MAX_OVERSHOOT : - 1 + (absVelocity - 1) * MAX_OVERSHOOT / 3, + 1 + (absVelocity - 1) * MAX_OVERSHOOT / 3, currentValue); double angleToPeak = PI_BY_2 - Math.asin(currentValue / maxValue); @@ -248,8 +256,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr if (currentFraction < LINEAR_SCALE_LIMIT) { mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR; - super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState, - velocity, isFling); return; } float extraValue = mAllAppsDampedInterpolator.getInterpolation(currentFraction) - 1; @@ -267,8 +273,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return; } mFinishFastOnSecondTouch = false; - super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState, - velocity, isFling); } @Override diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 25f2f87601..98597c86bd 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -749,6 +749,10 @@ public class WindowTransformSwipeHandler { } private void setupLauncherUiAfterSwipeUpAnimation() { + if (mLauncherTransitionController != null) { + mLauncherTransitionController.getAnimationPlayer().end(); + mLauncherTransitionController = null; + } mActivityControlHelper.onSwipeUpComplete(mActivity); // Animate the first icon. diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index bac8fc7461..6fb8a364c0 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -46,6 +46,7 @@ import android.util.FloatProperty; import android.util.SparseBooleanArray; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; @@ -275,6 +276,13 @@ public abstract class RecentsView } } + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + // Do not let touch escape to siblings below this view. + return true; + } + private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) { if (mPendingAnimation != null) { mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan)); diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 1a63326dd2..baf6d876b2 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -16,9 +16,12 @@ package com.android.launcher3; +import static android.view.MotionEvent.ACTION_DOWN; + import android.app.WallpaperManager; import android.content.Context; import android.graphics.Rect; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -173,6 +176,15 @@ public class ShortcutAndWidgetContainer extends ViewGroup { } } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) { + // Dont let children handle touch, if we are not visible. + return true; + } + return super.onInterceptTouchEvent(ev); + } + @Override public boolean shouldDelayChildPressedState() { return false; From 76642ae892b5e192164291f5b65b6f4c26298068 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 29 Mar 2018 18:25:52 -0700 Subject: [PATCH 30/81] Improve quick scrub auto-advance - Explicitly list thresholds, including for auto-advance - Thresholds for auto-advance are smaller, so you only reach them if you scroll to the edges of the track - Because auto-advance is it's own section, removed longer initial auto-advance delay - When moving out of auto-advance, stay on the same page instead of jumping back Bug: 70180755 Change-Id: I4a8926f9ca944ee619cc71a77b893be894248458 --- .../quickstep/QuickScrubController.java | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index d868d122b7..275fd29022 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -38,9 +38,14 @@ public class QuickScrubController implements OnAlarmListener { public static final int QUICK_SCRUB_START_DURATION = 210; + /** + * Snap to a new page when crossing these thresholds. The first and last auto-advance. + */ + private static final float[] QUICK_SCRUB_THRESHOLDS = new float[] { + 0.05f, 0.35f, 0.65f, 0.95f + }; + private static final boolean ENABLE_AUTO_ADVANCE = true; - private static final int NUM_QUICK_SCRUB_SECTIONS = 3; - private static final long INITIAL_AUTO_ADVANCE_DELAY = 1000; private static final long AUTO_ADVANCE_DELAY = 500; private static final int QUICKSCRUB_SNAP_DURATION_PER_PAGE = 325; private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60; @@ -52,7 +57,6 @@ public class QuickScrubController implements OnAlarmListener { private boolean mInQuickScrub; private int mQuickScrubSection; private boolean mStartedFromHome; - private boolean mHasAlarmRun; private boolean mFinishedTransitionToQuickScrub; public QuickScrubController(BaseActivity activity, RecentsView recentsView) { @@ -68,7 +72,6 @@ public class QuickScrubController implements OnAlarmListener { mInQuickScrub = true; mStartedFromHome = startingFromHome; mQuickScrubSection = 0; - mHasAlarmRun = false; mFinishedTransitionToQuickScrub = false; snapToNextTaskIfAvailable(); @@ -105,16 +108,23 @@ public class QuickScrubController implements OnAlarmListener { } public void onQuickScrubProgress(float progress) { - int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS); + int quickScrubSection = 0; + for (float threshold : QUICK_SCRUB_THRESHOLDS) { + if (progress < threshold) { + break; + } + quickScrubSection++; + } if (quickScrubSection != mQuickScrubSection) { + boolean cameFromAutoAdvance = mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length + || mQuickScrubSection == 0; int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection; - if (mFinishedTransitionToQuickScrub) { + if (mFinishedTransitionToQuickScrub && !cameFromAutoAdvance) { goToPageWithHaptic(pageToGoTo); } if (ENABLE_AUTO_ADVANCE) { - if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) { - mAutoAdvanceAlarm.setAlarm(mHasAlarmRun - ? AUTO_ADVANCE_DELAY : INITIAL_AUTO_ADVANCE_DELAY); + if (quickScrubSection == QUICK_SCRUB_THRESHOLDS.length || quickScrubSection == 0) { + mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY); } else { mAutoAdvanceAlarm.cancelAlarm(); } @@ -148,13 +158,12 @@ public class QuickScrubController implements OnAlarmListener { @Override public void onAlarm(Alarm alarm) { int currPage = mRecentsView.getNextPage(); - if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS + if (mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length && currPage < mRecentsView.getPageCount() - 1) { goToPageWithHaptic(currPage + 1); } else if (mQuickScrubSection == 0 && currPage > 0) { goToPageWithHaptic(currPage - 1); } - mHasAlarmRun = true; if (ENABLE_AUTO_ADVANCE) { mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY); } From ab7ddec88eddcc69ff9a60374942bd7a4ad34709 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 30 Mar 2018 11:46:23 -0700 Subject: [PATCH 31/81] Updating some icons Bug: 76435058 Change-Id: If2df50a738cd0bad5d0343cdd1a0542df1bee9d5 --- res/drawable/ic_setting.xml | 30 +++++++++++++++++++++--------- res/drawable/ic_wallpaper.xml | 13 +++++-------- res/drawable/ic_widget.xml | 9 ++++----- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml index 33cd6ce34a..a83aab3204 100644 --- a/res/drawable/ic_setting.xml +++ b/res/drawable/ic_setting.xml @@ -16,16 +16,28 @@ Copyright (C) 2016 The Android Open Source Project + android:pathData="M13.85,22.25h-3.7c-0.74,0-1.36-0.54-1.45-1.27l-0.27-1.89c-0.27-0.14-0.53-0.29-0.79-0.46l-1.8,0.72 + c-0.7,0.26-1.47-0.03-1.81-0.65L2.2,15.53c-0.35-0.66-0.2-1.44,0.36-1.88l1.53-1.19c-0.01-0.15-0.02-0.3-0.02-0.46 + c0-0.15,0.01-0.31,0.02-0.46l-1.52-1.19C1.98,9.9,1.83,9.09,2.2,8.47l1.85-3.19c0.34-0.62,1.11-0.9,1.79-0.63l1.81,0.73 + c0.26-0.17,0.52-0.32,0.78-0.46l0.27-1.91c0.09-0.7,0.71-1.25,1.44-1.25h3.7c0.74,0,1.36,0.54,1.45,1.27l0.27,1.89 + c0.27,0.14,0.53,0.29,0.79,0.46l1.8-0.72c0.71-0.26,1.48,0.03,1.82,0.65l1.84,3.18c0.36,0.66,0.2,1.44-0.36,1.88l-1.52,1.19 + c0.01,0.15,0.02,0.3,0.02,0.46s-0.01,0.31-0.02,0.46l1.52,1.19c0.56,0.45,0.72,1.23,0.37,1.86l-1.86,3.22 + c-0.34,0.62-1.11,0.9-1.8,0.63l-1.8-0.72c-0.26,0.17-0.52,0.32-0.78,0.46l-0.27,1.91C15.21,21.71,14.59,22.25,13.85,22.25z + M13.32,20.72c0,0.01,0,0.01,0,0.02L13.32,20.72z M10.68,20.7l0,0.02C10.69,20.72,10.69,20.71,10.68,20.7z M10.62,20.25h2.76 + l0.37-2.55l0.53-0.22c0.44-0.18,0.88-0.44,1.34-0.78l0.45-0.34l2.38,0.96l1.38-2.4l-2.03-1.58l0.07-0.56 + c0.03-0.26,0.06-0.51,0.06-0.78c0-0.27-0.03-0.53-0.06-0.78l-0.07-0.56l2.03-1.58l-1.39-2.4l-2.39,0.96l-0.45-0.35 + c-0.42-0.32-0.87-0.58-1.33-0.77L13.75,6.3l-0.37-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7,8.84,6.95,8.38,7.3L7.93,7.63 + L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47,6.06,11.74,6.06,12c0,0.26,0.02,0.53,0.06,0.78l0.07,0.56l-2.03,1.58 + l1.38,2.4l2.39-0.96l0.45,0.35c0.43,0.33,0.86,0.58,1.33,0.77l0.53,0.22L10.62,20.25z M18.22,17.72c0,0.01-0.01,0.02-0.01,0.03 + L18.22,17.72z M5.77,17.71l0.01,0.02C5.78,17.72,5.77,17.71,5.77,17.71z M3.93,9.47L3.93,9.47C3.93,9.47,3.93,9.47,3.93,9.47z + M18.22,6.27c0,0.01,0.01,0.02,0.01,0.02L18.22,6.27z M5.79,6.25L5.78,6.27C5.78,6.27,5.79,6.26,5.79,6.25z M13.31,3.28 + c0,0.01,0,0.01,0,0.02L13.31,3.28z M10.69,3.26l0,0.02C10.69,3.27,10.69,3.27,10.69,3.26z"/> + diff --git a/res/drawable/ic_wallpaper.xml b/res/drawable/ic_wallpaper.xml index 0c5a125b60..7fd93403c5 100644 --- a/res/drawable/ic_wallpaper.xml +++ b/res/drawable/ic_wallpaper.xml @@ -16,14 +16,11 @@ Copyright (C) 2016 The Android Open Source Project + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + android:pathData="M9,12.71l2.14,2.58l3-3.87L18,16.57H6L9,12.71z M5,5h6V3H5C3.9,3,3,3.9,3,5v6h2V5z M19,19h-6v2h6c1.1,0,2-0.9,2-2v-6h-2V19z + M5,19v-6H3v6c0,1.1,0.9,2,2,2h6v-2H5z M19,5v6h2V5c0-1.1-0.9-2-2-2h-6v2H19z M16,9c0.55,0,1-0.45,1-1s-0.45-1-1-1 + c-0.55,0-1,0.45-1,1S15.45,9,16,9z"/> diff --git a/res/drawable/ic_widget.xml b/res/drawable/ic_widget.xml index 4bb23b3f4b..3ebbb68bb9 100644 --- a/res/drawable/ic_widget.xml +++ b/res/drawable/ic_widget.xml @@ -16,11 +16,10 @@ Copyright (C) 2016 The Android Open Source Project + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + android:pathData="M16.66,4.52l2.83,2.83l-2.83,2.83l-2.83-2.83L16.66,4.52 M9,5v4H5V5H9 M19,15v4h-4v-4H19 M9,15v4H5v-4H9 M16.66,1.69 + L11,7.34L16.66,13l5.66-5.66L16.66,1.69L16.66,1.69z M11,3H3v8h8V7.34V3L11,3z M21,13h-4.34H13v8h8V13L21,13z M11,13H3v8h8V13L11,13z"/> From 2c09d2f972300b7ab4eb4491c6e61732e207c37b Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Fri, 30 Mar 2018 12:34:26 -0700 Subject: [PATCH 32/81] Fixing Transition Delay - Hot Launch From Recents on Pixel 1 Generating fake to-recents event upon pressing square button with no active task. Bug: 72967764 Test: Transition Delay - Hot Launch From Recents on Pixel 1 Change-Id: I36fdfe9d356c7678deee37b706f1abecfbfdc812 --- quickstep/src/com/android/quickstep/OverviewCommandHelper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 311411f4cf..958feb7dbe 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -50,6 +50,7 @@ import com.android.launcher3.states.InternalStateHandler; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper; import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper; +import com.android.quickstep.util.SysuiEventLogger; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; @@ -271,6 +272,7 @@ public class OverviewCommandHelper extends InternalStateHandler { return; } if (helper.switchToRecentsIfVisible()) { + SysuiEventLogger.writeDummyRecentsTransition(0); return; } From 953a8eb35c0db47da8812eb1a767b83bdb9979f3 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 30 Mar 2018 16:03:39 -0700 Subject: [PATCH 33/81] Fix crash when swiping up from task that doesn't appear in the list Bug: 74567248 Test: Clear all tasks, open assistant and swipe up Change-Id: Ie5e81ffbc921f76eb6b279f38b5e7aa423fc5af2 --- .../WindowTransformSwipeHandler.java | 20 +++++++++++-------- .../android/quickstep/views/RecentsView.java | 7 +++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 98597c86bd..33f13100ce 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -520,14 +520,18 @@ public class WindowTransformSwipeHandler { // Make sure the window follows the first task if it moves, e.g. during quick scrub. View firstTask = mRecentsView.getPageAt(0); - int scrollForFirstTask = mRecentsView.getScrollForPage(0); - int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX()); - synchronized (mTargetRect) { - mTargetRect.set(mInitialTargetRect); - Utilities.scaleRectFAboutCenter(mTargetRect, firstTask.getScaleX()); - float offsetX = offsetFromFirstTask + firstTask.getTranslationX(); - float offsetY = mRecentsView.getTranslationY(); - mTargetRect.offset(offsetX, offsetY); + // The first task may be null if we are swiping up from a task that does not + // appear in the list (ie. the assistant) + if (firstTask != null) { + int scrollForFirstTask = mRecentsView.getScrollForPage(0); + int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX()); + synchronized (mTargetRect) { + mTargetRect.set(mInitialTargetRect); + Utilities.scaleRectFAboutCenter(mTargetRect, firstTask.getScaleX()); + float offsetX = offsetFromFirstTask + firstTask.getTranslationX(); + float offsetY = mRecentsView.getTranslationY(); + mTargetRect.offset(offsetX, offsetY); + } } if (mRecentsAnimationWrapper.controller != null) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 6fb8a364c0..ab76e407ae 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -569,8 +569,11 @@ public abstract class RecentsView // Load the tasks (if the loading is already mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); - // Hide the task that we are animating into - getPageAt(mCurrentPage).setAlpha(0); + // Hide the task that we are animating into, ignore if there is no associated task (ie. the + // assistant) + if (getPageAt(mCurrentPage) != null) { + getPageAt(mCurrentPage).setAlpha(0); + } } public QuickScrubController getQuickScrubController() { From ac2042a40a42fcdc483cad512c40291d7f41070a Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Thu, 29 Mar 2018 18:44:19 -0700 Subject: [PATCH 34/81] Accessibility options for a task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list is: Close [task] Also making a current task in carousel get accessibility focus. This prevents losing focus after closing a task, and makes sense generally. Bug: 72409756 Test: Manual Change-Id: I2cfdfd4693a255f63417d922cb6aa4841db1d3c3 --- quickstep/res/layout/task.xml | 1 + quickstep/res/values/strings.xml | 3 ++ .../android/quickstep/views/RecentsView.java | 7 +++ .../android/quickstep/views/TaskMenuView.java | 2 +- .../com/android/quickstep/views/TaskView.java | 44 +++++++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 0ac2b11030..b8b360a48e 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -28,5 +28,6 @@ android:id="@+id/icon" android:layout_width="@dimen/task_thumbnail_icon_size" android:layout_height="@dimen/task_thumbnail_icon_size" + android:importantForAccessibility="no" android:layout_gravity="top|center_horizontal" /> \ No newline at end of file diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index bd37a06aed..7ba91b3db5 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -35,4 +35,7 @@ No recent items + + + Close \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7615e9c49c..50a32e64bc 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -49,6 +49,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; @@ -943,4 +944,10 @@ public abstract class RecentsView }); return mPendingAnimation; } + + @Override + protected void notifyPageSwitchListener(int prevPage) { + super.notifyPageSwitchListener(prevPage); + getChildAt(mCurrentPage).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); + } } diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 30cbcdf674..dd90c8867d 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -51,7 +51,7 @@ public class TaskMenuView extends AbstractFloatingView { private static final Rect sTempRect = new Rect(); /** Note that these will be shown in order from top to bottom, if available for the task. */ - private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] { + public static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] { new TaskSystemShortcut.AppInfo(), new TaskSystemShortcut.SplitScreen(), new TaskSystemShortcut.Pin(), diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index a701862a82..57516b09fa 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -22,10 +22,12 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.os.Bundle; import android.os.Handler; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; @@ -33,6 +35,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.quickstep.RecentsAnimationInterpolator; +import com.android.quickstep.TaskSystemShortcut; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; import com.android.systemui.shared.recents.model.Task; @@ -219,4 +222,45 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback view.getHeight(), mRadius); } } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + + info.addAction( + new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task, + getContext().getText(R.string.accessibility_close_task))); + + final Context context = getContext(); + final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(context); + for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) { + OnClickListener onClickListener = menuOption.getOnClickListener(activity, this); + if (onClickListener != null) { + info.addAction(new AccessibilityNodeInfo.AccessibilityAction(menuOption.labelResId, + context.getText(menuOption.labelResId))); + } + } + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (action == R.string.accessibility_close_task) { + ((RecentsView) getParent()).dismissTask(this, true /*animateTaskView*/, + true /*removeTask*/); + return true; + } + + for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) { + if (action == menuOption.labelResId) { + OnClickListener onClickListener = menuOption.getOnClickListener( + BaseDraggingActivity.fromContext(getContext()), this); + if (onClickListener != null) { + onClickListener.onClick(this); + } + return true; + } + } + + return super.performAccessibilityAction(action, arguments); + } } From ea4eceeba79faeb59f8ac33d1a12dee0e0f8bd75 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 1 Apr 2018 02:13:44 -0700 Subject: [PATCH 35/81] Import translations. DO NOT MERGE Change-Id: I9661c8c23d5c3f6390283edb3fba1eab99e5d997 Auto-generated-cl: translation import --- quickstep/res/values-af/strings.xml | 6 ++---- quickstep/res/values-am/strings.xml | 6 ++---- quickstep/res/values-ar/strings.xml | 6 ++---- quickstep/res/values-az/strings.xml | 6 ++---- quickstep/res/values-b+sr+Latn/strings.xml | 6 ++---- quickstep/res/values-bg/strings.xml | 6 ++---- quickstep/res/values-bs/strings.xml | 6 ++---- quickstep/res/values-cs/strings.xml | 6 ++---- quickstep/res/values-el/strings.xml | 6 ++---- quickstep/res/values-fa/strings.xml | 6 ++---- quickstep/res/values-gl/strings.xml | 6 ++---- quickstep/res/values-hr/strings.xml | 6 ++---- quickstep/res/values-km/strings.xml | 6 ++---- quickstep/res/values-kn/strings.xml | 6 ++---- quickstep/res/values-lt/strings.xml | 6 ++---- quickstep/res/values-lv/strings.xml | 6 ++---- quickstep/res/values-mk/strings.xml | 6 ++---- quickstep/res/values-ml/strings.xml | 6 ++---- quickstep/res/values-my/strings.xml | 6 ++---- quickstep/res/values-ne/strings.xml | 6 ++---- quickstep/res/values-pt/strings.xml | 6 ++---- quickstep/res/values-ru/strings.xml | 6 ++---- quickstep/res/values-si/strings.xml | 6 ++---- quickstep/res/values-sk/strings.xml | 6 ++---- quickstep/res/values-sl/strings.xml | 6 ++---- quickstep/res/values-sq/strings.xml | 6 ++---- quickstep/res/values-sr/strings.xml | 6 ++---- quickstep/res/values-sw/strings.xml | 6 ++---- quickstep/res/values-te/strings.xml | 6 ++---- quickstep/res/values-th/strings.xml | 6 ++---- quickstep/res/values-tl/strings.xml | 6 ++---- quickstep/res/values-tr/strings.xml | 6 ++---- quickstep/res/values-uk/strings.xml | 6 ++---- quickstep/res/values-zh-rHK/strings.xml | 6 ++---- quickstep/res/values-zh-rTW/strings.xml | 6 ++---- quickstep/res/values-zu/strings.xml | 6 ++---- res/values-es/strings.xml | 4 ++-- 37 files changed, 74 insertions(+), 146 deletions(-) diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index 415a33ece7..6196894191 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -22,8 +22,6 @@ "Verdeelde skerm" "Speld vas" "Swiep van onder af op om programme te wissel" - - - - + "Oorsig" + "Geen onlangse items nie" diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 663d23623c..5a892ad9f8 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -22,8 +22,6 @@ "የተከፈለ ማያ ገጽ" "ሰካ" "መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ" - - - - + "ማጠቃለያ" + "ምንም የቅርብ ጊዜ ንጥሎች የሉም" diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index 711d02be4b..3d83fcb7da 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -22,8 +22,6 @@ "تقسيم الشاشة" "تثبيت" "التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات" - - - - + "نظرة عامة" + "ليست هناك عناصر تم استخدامها مؤخرًا" diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index f5c9b93eb9..bede24b6fe 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -22,8 +22,6 @@ "Bölünmüş ekran" "Sancın" "Tətbiqləri dəyişmək üçün aşağıdan yuxarı doğru sürüşdürün" - - - - + "İcmal" + "Son elementlər yoxdur" diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index 6e3a76da51..b2f8b7ab08 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -22,8 +22,6 @@ "Podeljeni ekran" "Zakači" "Prevucite nagore da biste prešli na drugu aplikaciju" - - - - + "Pregled" + "Nema nedavnih stavki" diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index 5f4387e27b..bbf73c06ae 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -22,8 +22,6 @@ "Разделен екран" "Фиксиране" "Прекарайте пръст нагоре от долната част, за да превключите между приложенията" - - - - + "Общ преглед" + "Няма скорошни елементи" diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index 1b10f6e410..a6bbc24d62 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -22,8 +22,6 @@ "Način rada podijeljenog ekrana" "Zakači" "Prevucite od dolje prema gore za promjenu aplikacije" - - - - + "Pregled" + "Nema nedavnih stavki" diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index f0283e5f86..b6f99db3e0 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -22,8 +22,6 @@ "Rozdělená obrazovka" "PIN" "Aplikace můžete přepínat přejetím zdola nahoru" - - - - + "Přehled" + "Žádné nedávné položky" diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index ceffc4ba56..bdee73b4d4 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -22,8 +22,6 @@ "Διαχωρισμός οθόνης" "Καρφίτσωμα" "Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών" - - - - + "Επισκόπηση" + "Δεν υπάρχουν πρόσφατα στοιχεία" diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index a2be1fcd2b..75d2e7eaf3 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -22,8 +22,6 @@ "تقسیم صفحه" "پین" "برای تغییر برنامه‌ها،‌ از پایین تند به بالا بکشید" - - - - + "نمای کلی" + "بدون موارد اخیر" diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index 388f3aadb2..9c5c0ee832 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -22,8 +22,6 @@ "Pantalla dividida" "Fixar" "Pasa o dedo cara arriba desde a parte inferior para cambiar de aplicacións" - - - - + "Visión xeral" + "Non hai elementos recentes" diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index aa9307df68..ab533618fa 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -22,8 +22,6 @@ "Podijeljeni zaslon" "Prikvači" "Prijeđite prstom od dna prema gore da biste promijenili aplikaciju" - - - - + "Pregled" + "Nema nedavnih stavki" diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index 7c5f599552..5b1c55c5d5 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -22,8 +22,6 @@ "មុខងារ​បំបែកអេក្រង់" "ដៅ" "អូស​ពី​ក្រោម​ឡើង​លើ ដើម្បី​ប្ដូរ​កម្មវិធី" - - - - + "ទិដ្ឋភាពរួម" + "មិនមានធាតុថ្មីៗទេ" diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 4c0ac63eb3..303949100e 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -22,8 +22,6 @@ "ಪರದೆಯನ್ನು ಬೇರ್ಪಡಿಸಿ" "ಪಿನ್ ಮಾಡಿ" "ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ" - - - - + "ಅವಲೋಕನ" + "ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ" diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index 924e4d8bd6..06eeb5a8f9 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -22,8 +22,6 @@ "Skaidyti ekraną" "Prisegti" "Perbraukite aukštyn iš apačios, kad perjungtumėte programas" - - - - + "Apžvalga" + "Nėra jokių naujausių elementų" diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index 86a15b7a7b..6b869917b5 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -22,8 +22,6 @@ "Sadalīt ekrānu" "Piespraust" "Lai pārslēgtu lietotnes, velciet augšup no apakšdaļas." - - - - + "Pārskats" + "Nav nesenu vienumu." diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index 633fd4423f..a86a2a2e28 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -22,8 +22,6 @@ "Поделен екран" "Прикачување" "Повлечете нагоре од дното за да ги смените апликациите" - - - - + "Преглед" + "Нема неодамнешни ставки" diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 3981e805eb..4ff880cfd2 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -22,8 +22,6 @@ "സ്‌ക്രീൻ വിഭജിക്കുക" "പിൻ ചെയ്യുക" "ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക" - - - - + "അവലോകനം" + "സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല" diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index 38b78d9ddf..c7662a86b9 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -22,8 +22,6 @@ "မျက်နှာပြင် ခွဲ၍ပြသခြင်း" "ပင်ထိုးခြင်း" "အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ" - - - - + "အနှစ်ချုပ်" + "မကြာမီကဖွင့်ထားသည်များ မရှိပါ" diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index 45387ce0b3..73738f5024 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -22,8 +22,6 @@ "स्क्रिन विभाजन गर्नुहोस्" "पिन गर्नुहोस्" "अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्" - - - - + "परिदृश्य" + "हालसालैको कुनै पनि वस्तु छैन" diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index 5c71fdb356..cc54aa7b2a 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -22,8 +22,6 @@ "Tela dividida" "Fixar" "Deslize de baixo para cima para alternar entre apps" - - - - + "Visão geral" + "Nenhum item recente" diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index 922f940334..a0de61a146 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -22,8 +22,6 @@ "Разделить экран" "Блокировать" "Чтобы переключить приложение, проведите по экрану снизу вверх" - - - - + "Обзор" + "Недавних приложений нет." diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index 8c3c4a64e5..ad291165e3 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -22,8 +22,6 @@ "බෙදුම් තිරය" "අමුණන්න" "යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න" - - - - + "දළ විශ්ලේෂණය" + "මෑත අයිතම නැත" diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index 1faccf8702..4e7467f1e8 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -22,8 +22,6 @@ "Rozdeliť obrazovku" "Pripnúť" "Aplikácie môžete prepínať potiahnutím prstom zdola nahor" - - - - + "Prehľad" + "Žiadne nedávne položky" diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index 19ad7eb5c4..d19b69f49e 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -22,8 +22,6 @@ "Razdeljen zaslon" "Pripni" "Če želite preklopiti med aplikacijami, z dna zaslona s prstom povlecite navzgor" - - - - + "Pregled" + "Ni nedavnih elementov" diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index cec4668364..e9dc7769c2 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -22,8 +22,6 @@ "Ekrani i ndarë" "Gozhdo" "Rrëshqit larg nga poshtë për të ndryshuar aplikacionet" - - - - + "Përmbledhja" + "Nuk ka asnjë artikull të fundit" diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index 9c031e9bce..ad10d4c998 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -22,8 +22,6 @@ "Подељени екран" "Закачи" "Превуците нагоре да бисте прешли на другу апликацију" - - - - + "Преглед" + "Нема недавних ставки" diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index dc1ad83360..7f453c67a0 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -22,8 +22,6 @@ "Gawa skrini" "Bandika" "Telezesha kidole juu kuanzia chini ili ubadilishe programu" - - - - + "Muhtasari" + "Hakuna vipengee vya hivi karibuni" diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 9c353af6a2..543b225a5b 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -22,8 +22,6 @@ "స్క్రీన్‌ని విభజించు" "పిన్ చేయి" "యాప్‌లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి" - - - - + "అవలోకనం" + "ఇటీవలి అంశాలు ఏవీ లేవు" diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 4e88146c00..92fa179f1b 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -22,8 +22,6 @@ "แยกหน้าจอ" "ตรึง" "เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป" - - - - + "ภาพรวม" + "ไม่มีรายการล่าสุด" diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index 5540f089ce..136cee41de 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -22,8 +22,6 @@ "Hatiin ang screen" "I-pin" "Mag-swipe pataas mula sa ibaba para lumipat ng app" - - - - + "Overview" + "Walang kamakailang item" diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index dc5c45fb8e..542f26243f 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -22,8 +22,6 @@ "Bölünmüş ekran" "Sabitle" "Uygulamaları değiştirmek için alttan yukarı kaydırın" - - - - + "Genel bakış" + "Yeni öğe yok" diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 21f7c746e0..44c04c3e25 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -22,8 +22,6 @@ "Розділити екран" "Закріпити" "Щоб переходити між додатками, проводьте пальцем знизу вгору" - - - - + "Огляд" + "Немає нещодавніх додатків" diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index 1443cba45d..bdf27ede9b 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -22,8 +22,6 @@ "分割畫面" "固定" "從螢幕底部向上快速滑動,即可切換應用程式" - - - - + "總覽" + "最近沒有任何項目" diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index c93c537991..b7528cafd9 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -22,8 +22,6 @@ "分割畫面" "固定" "從畫面底部向上滑動以切換應用程式" - - - - + "總覽" + "最近沒有任何項目" diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index 56172b4f4b..e43e98677d 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -22,8 +22,6 @@ "Hlukanisa isikrini" "Phina" "Swayiphela phezulu kusukela phansi ukuze ushintshe izinhlelo zokusebenza" - - - - + "Buka konke" + "Azikho izinto zakamuva" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 877d1501d6..5b948da351 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -40,8 +40,8 @@ "No se han encontrado aplicaciones que contengan \"%1$s\"" "Buscar más aplicaciones" "Notificaciones" - "Mantén pulsado el acceso directo que quieras." - "Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas." + "Mantén pulsado para elegir un acceso directo." + "Toca dos veces y mantén pulsado para elegir un acceso directo o utilizar acciones personalizadas." "No queda espacio en la pantalla de inicio." "La bandeja de favoritos está completa" "Lista de aplicaciones" From e1a9c7ed3f08ad0cc93016928260e7690dcdc32d Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Fri, 30 Mar 2018 17:09:06 -0700 Subject: [PATCH 36/81] Added two touch slops for easier home press (3/3) The first slop starts the drag either for quick step or scrub. At this point either launcher can animate swipe up or the home button moves for scrub, however the home button is still active and can be pressed or long pressed. The second slop is for activating quick step or scrub. Similar to before when an operation has activated, the home button cannot be pressed or long pressed. This allows the home button to have a larger area to be clicked. Change-Id: Ie792845a09ecf5d8bdbeae9e8ef7210e2299c69d Fixes: 76430825 Test: scrub or swipe up --- quickstep/libs/sysui_shared.jar | Bin 118578 -> 119143 bytes .../quickstep/OtherActivityTouchConsumer.java | 46 ++++++++++-------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index e414fa033b138feadabe8523e351790d6566f3ae..2b9db35bc007f5e20e871b34321af7a01b7db2a0 100644 GIT binary patch delta 12964 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 QUICK_STEP_DRAG_SLOP_PX) { + mPassedInitialSlop = true; + mStartDisplacement = displacement; - if (mGestureStarted && mInteractionHandler != null) { + // If we deferred starting the window animation on touch down, then + // start tracking now + if (mIsDeferredDownTarget) { + startTouchTrackingForWindowAnimation(ev.getEventTime()); + } + } + + if (mPassedInitialSlop && mInteractionHandler != null) { // Move - float displacement = getDisplacement(ev.getX(pointerIndex), - ev.getY(pointerIndex)); mInteractionHandler.updateDisplacement(displacement - mStartDisplacement); } break; @@ -179,7 +187,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC return; } // Notify the handler that the gesture has actually started - mGestureStarted = true; mInteractionHandler.onGestureStarted(); } @@ -244,10 +251,12 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC if (Looper.myLooper() != Looper.getMainLooper()) { startActivity.run(); - try { - drawWaitLock.await(LAUNCHER_DRAW_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (Exception e) { - // We have waited long enough for launcher to draw + if (!mIsDeferredDownTarget) { + try { + drawWaitLock.await(LAUNCHER_DRAW_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + // We have waited long enough for launcher to draw + } } } else { // We should almost always get touch-town on background thread. This is an edge case @@ -261,7 +270,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC * the animation can still be running. */ private void finishTouchTracking() { - if (mGestureStarted && mInteractionHandler != null) { + if (mPassedInitialSlop && mInteractionHandler != null) { mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); @@ -323,17 +332,12 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC @Override public void onQuickStep(float eventX, float eventY, long eventTime) { - float displacement = getDisplacement(eventX, eventY); - mStartDisplacement = Math.signum(displacement) * mTouchSlop; - if (mIsDeferredDownTarget) { - // If we deferred starting the window animation on touch down, then - // start tracking now - startTouchTrackingForWindowAnimation(eventTime); - } notifyGestureStarted(); } - private float getDisplacement(float eventX, float eventY) { + private float getDisplacement(MotionEvent ev) { + float eventX = ev.getX(); + float eventY = ev.getY(); float displacement = eventY - mDownPos.y; if (isNavBarOnRight()) { displacement = eventX - mDownPos.x; From 2fd7a8bc596f6ec28098b8566203d3b552ac2d39 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 30 Mar 2018 17:10:13 -0700 Subject: [PATCH 37/81] Updating the UI of the options popup to make it look similar to icon popup Bug: 77327164 Change-Id: I3580df8bf8a43cb44123f203ffed9a85fa33aea7 --- res/layout/longpress_options_menu.xml | 84 +-- res/values/dimens.xml | 1 + .../launcher3/BaseDraggingActivity.java | 2 +- src/com/android/launcher3/Launcher.java | 26 +- src/com/android/launcher3/Workspace.java | 5 + .../notification/NotificationItemView.java | 3 +- .../android/launcher3/popup/ArrowPopup.java | 470 +++++++++++++++++ .../popup/PopupContainerWithArrow.java | 480 ++---------------- .../touch/WorkspaceTouchListener.java | 2 +- .../views/LauncherDragIndicator.java | 9 +- .../launcher3/views/OptionsPopupView.java | 293 ++++------- 11 files changed, 638 insertions(+), 737 deletions(-) create mode 100644 src/com/android/launcher3/popup/ArrowPopup.java diff --git a/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml index 71d117af86..168dbc3a2e 100644 --- a/res/layout/longpress_options_menu.xml +++ b/res/layout/longpress_options_menu.xml @@ -15,83 +15,11 @@ --> - - - - - - - - - - - - - - - - - - - \ No newline at end of file + android:orientation="vertical" /> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a2f7286794..b1ad11ef05 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -222,4 +222,5 @@ 24dp + 32dp diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 4c11fe66e0..bde9ad3109 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -47,7 +47,7 @@ public abstract class BaseDraggingActivity extends BaseActivity private static final String TAG = "BaseDraggingActivity"; // The Intent extra that defines whether to ignore the launch animation - protected static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = + public static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION"; // When starting an action mode, setting this tag will cause the action mode to be cancelled diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index e2f748837c..ccc774a9ec 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1634,30 +1634,6 @@ public class Launcher extends BaseDraggingActivity } } - /** - * Event handler for the wallpaper picker button that appears after a long press - * on the home screen. - */ - public void onClickWallpaperPicker(View v) { - if (!Utilities.isWallpaperAllowed(this)) { - Toast.makeText(this, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show(); - return; - } - int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen()); - float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll); - Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER) - .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset); - - String pickerPackage = getString(R.string.wallpaper_picker_package); - if (!TextUtils.isEmpty(pickerPackage)) { - intent.setPackage(pickerPackage); - } else { - // If there is no target package, use the default intent chooser animation - intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true); - } - startActivitySafely(v, intent, null); - } - @TargetApi(Build.VERSION_CODES.M) @Override public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) { @@ -2415,7 +2391,7 @@ public class Launcher extends BaseDraggingActivity // Setting the touch point to (-1, -1) will show the options popup in the center of // the screen. - OptionsPopupView.show(this, -1, -1); + OptionsPopupView.showDefaultOptions(this, -1, -1); } return true; } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 34ae8ea3d1..a208c7a54c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -349,6 +349,11 @@ public class Workspace extends PagedView } } + public float getWallpaperOffsetForCenterPage() { + int pageScroll = getScrollForPage(getPageNearestToCenterOfScreen()); + return mWallpaperOffset.wallpaperOffsetForScroll(pageScroll); + } + public Rect estimateItemPosition(CellLayout cl, int hCell, int vCell, int hSpan, int vSpan) { Rect r = new Rect(); cl.cellToRect(hCell, vCell, hSpan, vSpan, r); diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index 2fefa85ea3..32410a64b8 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -20,7 +20,6 @@ import android.app.Notification; import android.content.Context; import android.graphics.Color; import android.graphics.Rect; -import android.support.annotation.Nullable; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; @@ -83,7 +82,7 @@ public class NotificationItemView { public void addGutter() { if (mGutter == null) { - mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter); + mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter, mContainer); } } diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java new file mode 100644 index 0000000000..bd08aaa0eb --- /dev/null +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2018 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.popup; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.CornerPathEffect; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.ShapeDrawable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.accessibility.AccessibilityEvent; +import android.view.animation.AccelerateDecelerateInterpolator; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAnimUtils; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.RevealOutlineAnimation; +import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.graphics.TriangleShape; +import com.android.launcher3.util.Themes; + +import java.util.ArrayList; +import java.util.Collections; + +import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; + +/** + * A container for shortcuts to deep links and notifications associated with an app. + */ +public abstract class ArrowPopup extends AbstractFloatingView { + + private final Rect mTempRect = new Rect(); + + protected final LayoutInflater mInflater; + private final float mOutlineRadius; + protected final Launcher mLauncher; + protected final boolean mIsRtl; + + private final int mArrayOffset; + private final View mArrow; + + protected boolean mIsLeftAligned; + protected boolean mIsAboveIcon; + private int mGravity; + + protected Animator mOpenCloseAnimator; + protected boolean mDeferContainerRemoval; + private final Rect mStartRect = new Rect(); + private final Rect mEndRect = new Rect(); + + public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mInflater = LayoutInflater.from(context); + mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius); + mLauncher = Launcher.getLauncher(context); + mIsRtl = Utilities.isRtl(getResources()); + + setClipToOutline(true); + setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius); + } + }); + + // Initialize arrow view + final Resources resources = getResources(); + final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width); + final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height); + mArrow = new View(context); + mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight)); + mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset); + } + + public ArrowPopup(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ArrowPopup(Context context) { + this(context, null, 0); + } + + @Override + protected void handleClose(boolean animate) { + if (animate) { + animateClose(); + } else { + closeComplete(); + } + } + + public T inflateAndAdd(int resId, ViewGroup container) { + View view = mInflater.inflate(resId, container, false); + container.addView(view); + return (T) view; + } + + /** + * Called when all view inflation and reordering in complete. + */ + protected void onInflationComplete(boolean isReversed) { } + + /** + * Shows the popup at the desired location, optionally reversing the children. + * @param viewsToFlip number of views from the top to to flip in case of reverse order + */ + protected void reorderAndShow(int viewsToFlip) { + setVisibility(View.INVISIBLE); + mIsOpen = true; + mLauncher.getDragLayer().addView(this); + orientAboutObject(); + + boolean reverseOrder = mIsAboveIcon; + if (reverseOrder) { + int count = getChildCount(); + ArrayList allViews = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + if (i == viewsToFlip) { + Collections.reverse(allViews); + } + allViews.add(getChildAt(i)); + } + Collections.reverse(allViews); + removeAllViews(); + for (int i = 0; i < count; i++) { + addView(allViews.get(i)); + } + + orientAboutObject(); + } + onInflationComplete(reverseOrder); + + // Add the arrow. + final Resources res = getResources(); + final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart() + ? R.dimen.popup_arrow_horizontal_center_start + : R.dimen.popup_arrow_horizontal_center_end); + final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2; + mLauncher.getDragLayer().addView(mArrow); + DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams(); + if (mIsLeftAligned) { + mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth); + } else { + mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth); + } + + if (Gravity.isVertical(mGravity)) { + // This is only true if there wasn't room for the container next to the icon, + // so we centered it instead. In that case we don't want to showDefaultOptions the arrow. + mArrow.setVisibility(INVISIBLE); + } else { + ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create( + arrowLp.width, arrowLp.height, !mIsAboveIcon)); + Paint arrowPaint = arrowDrawable.getPaint(); + arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary)); + // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable. + int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius); + arrowPaint.setPathEffect(new CornerPathEffect(radius)); + mArrow.setBackground(arrowDrawable); + mArrow.setElevation(getElevation()); + } + + mArrow.setPivotX(arrowLp.width / 2); + mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height); + + animateOpen(); + } + + protected boolean isAlignedWithStart() { + return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl; + } + + /** + * Provide the location of the target object relative to the dragLayer. + */ + protected abstract void getTargetObjectLocation(Rect outPos); + + /** + * Orients this container above or below the given icon, aligning with the left or right. + * + * These are the preferred orientations, in order (RTL prefers right-aligned over left): + * - Above and left-aligned + * - Above and right-aligned + * - Below and left-aligned + * - Below and right-aligned + * + * So we always align left if there is enough horizontal space + * and align above if there is enough vertical space. + */ + protected void orientAboutObject() { + measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + int width = getMeasuredWidth(); + int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset + + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding); + int height = getMeasuredHeight() + extraVerticalSpace; + + getTargetObjectLocation(mTempRect); + DragLayer dragLayer = mLauncher.getDragLayer(); + Rect insets = dragLayer.getInsets(); + + // Align left (right in RTL) if there is room. + int leftAlignedX = mTempRect.left; + int rightAlignedX = mTempRect.right - width; + int x = leftAlignedX; + boolean canBeLeftAligned = leftAlignedX + width + insets.left + < dragLayer.getRight() - insets.right; + boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left; + if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) { + x = rightAlignedX; + } + mIsLeftAligned = x == leftAlignedX; + + // Offset x so that the arrow and shortcut icons are center-aligned with the original icon. + int iconWidth = mTempRect.width(); + Resources resources = getResources(); + int xOffset; + if (isAlignedWithStart()) { + // Aligning with the shortcut icon. + int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size); + int shortcutPaddingStart = resources.getDimensionPixelSize( + R.dimen.popup_padding_start); + xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart; + } else { + // Aligning with the drag handle. + int shortcutDragHandleWidth = resources.getDimensionPixelSize( + R.dimen.deep_shortcut_drag_handle_size); + int shortcutPaddingEnd = resources.getDimensionPixelSize( + R.dimen.popup_padding_end); + xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd; + } + x += mIsLeftAligned ? xOffset : -xOffset; + + // Open above icon if there is room. + int iconHeight = mTempRect.height(); + int y = mTempRect.top - height; + mIsAboveIcon = y > dragLayer.getTop() + insets.top; + if (!mIsAboveIcon) { + y = mTempRect.top + iconHeight + extraVerticalSpace; + } + + // Insets are added later, so subtract them now. + if (mIsRtl) { + x += insets.right; + } else { + x -= insets.left; + } + y -= insets.top; + + mGravity = 0; + if (y + height > dragLayer.getBottom() - insets.bottom) { + // The container is opening off the screen, so just center it in the drag layer instead. + mGravity = Gravity.CENTER_VERTICAL; + // Put the container next to the icon, preferring the right side in ltr (left in rtl). + int rightSide = leftAlignedX + iconWidth - insets.left; + int leftSide = rightAlignedX - iconWidth - insets.left; + if (!mIsRtl) { + if (rightSide + width < dragLayer.getRight()) { + x = rightSide; + mIsLeftAligned = true; + } else { + x = leftSide; + mIsLeftAligned = false; + } + } else { + if (leftSide > dragLayer.getLeft()) { + x = leftSide; + mIsLeftAligned = false; + } else { + x = rightSide; + mIsLeftAligned = true; + } + } + mIsAboveIcon = true; + } + + setX(x); + if (Gravity.isVertical(mGravity)) { + return; + } + + DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); + DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams(); + if (mIsAboveIcon) { + arrowLp.gravity = lp.gravity = Gravity.BOTTOM; + lp.bottomMargin = + mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top; + arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom; + } else { + arrowLp.gravity = lp.gravity = Gravity.TOP; + lp.topMargin = y + insets.top; + arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset; + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + // enforce contained is within screen + DragLayer dragLayer = mLauncher.getDragLayer(); + if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) { + // If we are still off screen, center horizontally too. + mGravity |= Gravity.CENTER_HORIZONTAL; + } + + if (Gravity.isHorizontal(mGravity)) { + setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2); + mArrow.setVisibility(INVISIBLE); + } + if (Gravity.isVertical(mGravity)) { + setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2); + } + } + + private void animateOpen() { + setVisibility(View.VISIBLE); + + final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet(); + final Resources res = getResources(); + final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration); + final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator(); + + // Rectangular reveal. + final ValueAnimator revealAnim = createOpenCloseOutlineProvider() + .createRevealAnimator(this, false); + revealAnim.setDuration(revealDuration); + revealAnim.setInterpolator(revealInterpolator); + + Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1); + fadeIn.setDuration(revealDuration); + fadeIn.setInterpolator(revealInterpolator); + openAnim.play(fadeIn); + + // Animate the arrow. + mArrow.setScaleX(0); + mArrow.setScaleY(0); + Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1) + .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration)); + + openAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mOpenCloseAnimator = null; + sendCustomAccessibilityEvent( + ArrowPopup.this, + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, + getContext().getString(R.string.action_deep_shortcut)); + } + }); + + mOpenCloseAnimator = openAnim; + openAnim.playSequentially(revealAnim, arrowScale); + openAnim.start(); + } + + protected void animateClose() { + if (!mIsOpen) { + return; + } + mEndRect.setEmpty(); + if (getOutlineProvider() instanceof RevealOutlineAnimation) { + ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect); + } + if (mOpenCloseAnimator != null) { + mOpenCloseAnimator.cancel(); + } + mIsOpen = false; + + final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet(); + // Hide the arrow + closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0)); + closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0)); + + final Resources res = getResources(); + final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator(); + + // Rectangular reveal (reversed). + final ValueAnimator revealAnim = createOpenCloseOutlineProvider() + .createRevealAnimator(this, true); + revealAnim.setInterpolator(revealInterpolator); + closeAnim.play(revealAnim); + + Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0); + fadeOut.setInterpolator(revealInterpolator); + closeAnim.play(fadeOut); + + onCreateCloseAnimation(closeAnim); + closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration)); + closeAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mOpenCloseAnimator = null; + if (mDeferContainerRemoval) { + setVisibility(INVISIBLE); + } else { + closeComplete(); + } + } + }); + mOpenCloseAnimator = closeAnim; + closeAnim.start(); + } + + /** + * Called when creating the close transition allowing subclass can add additional animations. + */ + protected void onCreateCloseAnimation(AnimatorSet anim) { } + + private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() { + int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ? + R.dimen.popup_arrow_horizontal_center_start: + R.dimen.popup_arrow_horizontal_center_end); + if (!mIsLeftAligned) { + arrowCenterX = getMeasuredWidth() - arrowCenterX; + } + int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0; + + mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY); + if (mEndRect.isEmpty()) { + mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + + return new RoundedRectRevealOutlineProvider + (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect); + } + + /** + * Closes the popup without animation. + */ + protected void closeComplete() { + if (mOpenCloseAnimator != null) { + mOpenCloseAnimator.cancel(); + mOpenCloseAnimator = null; + } + mIsOpen = false; + mDeferContainerRemoval = false; + mLauncher.getDragLayer().removeView(this); + mLauncher.getDragLayer().removeView(mArrow); + } +} diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 033fdf8889..422a4ecd26 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -16,36 +16,28 @@ package com.android.launcher3.popup; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; +import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO; +import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; +import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; + import android.animation.AnimatorSet; import android.animation.LayoutTransition; -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; -import android.content.res.Resources; -import android.graphics.CornerPathEffect; -import android.graphics.Outline; -import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.ShapeDrawable; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; -import android.view.Gravity; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewOutlineProvider; -import android.view.accessibility.AccessibilityEvent; -import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.ImageView; import com.android.launcher3.AbstractFloatingView; @@ -56,20 +48,15 @@ import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.ItemInfo; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherModel; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; -import com.android.launcher3.anim.RevealOutlineAnimation; -import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; -import com.android.launcher3.graphics.TriangleShape; import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.notification.NotificationInfo; import com.android.launcher3.notification.NotificationItemView; @@ -79,85 +66,38 @@ import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.PackageUserKey; -import com.android.launcher3.util.Themes; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; -import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO; -import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; -import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; - /** * A container for shortcuts to deep links and notifications associated with an app. */ @TargetApi(Build.VERSION_CODES.N) -public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource, +public class PopupContainerWithArrow extends ArrowPopup implements DragSource, DragController.DragListener, View.OnLongClickListener, View.OnTouchListener { private final List mShortcuts = new ArrayList<>(); private final PointF mInterceptTouchDown = new PointF(); - private final Rect mTempRect = new Rect(); private final Point mIconLastTouchPos = new Point(); private final int mStartDragThreshold; - private final LayoutInflater mInflater; - private final float mOutlineRadius; - private final Launcher mLauncher; private final LauncherAccessibilityDelegate mAccessibilityDelegate; - private final boolean mIsRtl; - - private final int mArrayOffset; - private final View mArrow; private BubbleTextView mOriginalIcon; private NotificationItemView mNotificationItemView; + private int mNumNotifications; private ViewGroup mSystemShortcutContainer; - private boolean mIsLeftAligned; - protected boolean mIsAboveIcon; - private int mNumNotifications; - private int mGravity; - - protected Animator mOpenCloseAnimator; - protected boolean mDeferContainerRemoval; - private final Rect mStartRect = new Rect(); - private final Rect mEndRect = new Rect(); - public PopupContainerWithArrow(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mStartDragThreshold = getResources().getDimensionPixelSize( R.dimen.deep_shortcuts_start_drag_threshold); - mInflater = LayoutInflater.from(context); - mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius); - mLauncher = Launcher.getLauncher(context); mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher); - mIsRtl = Utilities.isRtl(getResources()); - - setClipToOutline(true); - setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius); - } - }); - - // Initialize arrow view - final Resources resources = getResources(); - final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width); - final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height); - mArrow = new View(context); - mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight)); - mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset); } public PopupContainerWithArrow(Context context, AttributeSet attrs) { @@ -222,21 +162,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra return false; } - @Override - protected void handleClose(boolean animate) { - if (animate) { - animateClose(); - } else { - closeComplete(); - } - } - - public T inflateAndAdd(int resId) { - View view = mInflater.inflate(resId, this, false); - addView(view); - return (T) view; - } - /** * Shows the notifications and deep shortcuts associated with {@param icon}. * @return the container if shown or null. @@ -267,13 +192,30 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra return container; } + @Override + protected void onInflationComplete(boolean isReversed) { + if (isReversed && mNotificationItemView != null) { + mNotificationItemView.inverseGutterMargin(); + } + + // Update dividers + int count = getChildCount(); + DeepShortcutView lastView = null; + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) { + if (lastView != null) { + lastView.setDividerVisibility(VISIBLE); + } + lastView = (DeepShortcutView) view; + lastView.setDividerVisibility(INVISIBLE); + } + } + } + private void populateAndShow(final BubbleTextView originalIcon, final List shortcutIds, final List notificationKeys, List systemShortcuts) { mNumNotifications = notificationKeys.size(); - - setVisibility(View.INVISIBLE); - mLauncher.getDragLayer().addView(this); - mOriginalIcon = originalIcon; // Add views @@ -295,17 +237,15 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } for (int i = shortcutIds.size(); i > 0; i--) { - mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut)); + mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut, this)); } updateHiddenShortcuts(); if (!systemShortcuts.isEmpty()) { - mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons); + mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this); for (SystemShortcut shortcut : systemShortcuts) { - View view = mInflater.inflate(R.layout.system_shortcut_icon_only, - mSystemShortcutContainer, false); - mSystemShortcutContainer.addView(view); - initializeSystemShortcut(view, shortcut); + initializeSystemShortcut( + R.layout.system_shortcut_icon_only, mSystemShortcutContainer, shortcut); } } } else if (!systemShortcuts.isEmpty()) { @@ -314,68 +254,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } for (SystemShortcut shortcut : systemShortcuts) { - initializeSystemShortcut(inflateAndAdd(R.layout.system_shortcut), shortcut); + initializeSystemShortcut(R.layout.system_shortcut, this, shortcut); } } - orientAboutIcon(); - boolean reverseOrder = mIsAboveIcon; - if (reverseOrder) { - int count = getChildCount(); - ArrayList allViews = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - if (i == viewsToFlip) { - Collections.reverse(allViews); - } - allViews.add(getChildAt(i)); - } - Collections.reverse(allViews); - removeAllViews(); - for (int i = 0; i < count; i++) { - addView(allViews.get(i)); - } - if (mNotificationItemView != null) { - mNotificationItemView.inverseGutterMargin(); - } - - orientAboutIcon(); - } - updateDividers(); - - // Add the arrow. - final Resources res = getResources(); - final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart() - ? R.dimen.popup_arrow_horizontal_center_start - : R.dimen.popup_arrow_horizontal_center_end); - final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2; - mLauncher.getDragLayer().addView(mArrow); - DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams(); - if (mIsLeftAligned) { - mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth); - } else { - mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth); - } - - if (Gravity.isVertical(mGravity)) { - // This is only true if there wasn't room for the container next to the icon, - // so we centered it instead. In that case we don't want to show the arrow. - mArrow.setVisibility(INVISIBLE); - } else { - ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create( - arrowLp.width, arrowLp.height, !mIsAboveIcon)); - Paint arrowPaint = arrowDrawable.getPaint(); - arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary)); - // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable. - int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius); - arrowPaint.setPathEffect(new CornerPathEffect(radius)); - mArrow.setBackground(arrowDrawable); - mArrow.setElevation(getElevation()); - } - - mArrow.setPivotX(arrowLp.width / 2); - mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height); - - animateOpen(); + reorderAndShow(viewsToFlip); ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag(); int numShortcuts = mShortcuts.size() + systemShortcuts.size(); @@ -401,189 +284,15 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra this, shortcutIds, mShortcuts, notificationKeys)); } - protected boolean isAlignedWithStart() { - return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl; - } - - /** - * Orients this container above or below the given icon, aligning with the left or right. - * - * These are the preferred orientations, in order (RTL prefers right-aligned over left): - * - Above and left-aligned - * - Above and right-aligned - * - Below and left-aligned - * - Below and right-aligned - * - * So we always align left if there is enough horizontal space - * and align above if there is enough vertical space. - */ - protected void orientAboutIcon() { - measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - int width = getMeasuredWidth(); - int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset - + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding); - int height = getMeasuredHeight() + extraVerticalSpace; - - DragLayer dragLayer = mLauncher.getDragLayer(); - dragLayer.getDescendantRectRelativeToSelf(mOriginalIcon, mTempRect); - Rect insets = dragLayer.getInsets(); - - // Align left (right in RTL) if there is room. - int leftAlignedX = mTempRect.left + mOriginalIcon.getPaddingLeft(); - int rightAlignedX = mTempRect.right - width - mOriginalIcon.getPaddingRight(); - int x = leftAlignedX; - boolean canBeLeftAligned = leftAlignedX + width + insets.left - < dragLayer.getRight() - insets.right; - boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left; - if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) { - x = rightAlignedX; - } - mIsLeftAligned = x == leftAlignedX; - - // Offset x so that the arrow and shortcut icons are center-aligned with the original icon. - int iconWidth = mOriginalIcon.getWidth() - - mOriginalIcon.getTotalPaddingLeft() - mOriginalIcon.getTotalPaddingRight(); - iconWidth *= mOriginalIcon.getScaleX(); - Resources resources = getResources(); - int xOffset; - if (isAlignedWithStart()) { - // Aligning with the shortcut icon. - int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size); - int shortcutPaddingStart = resources.getDimensionPixelSize( - R.dimen.popup_padding_start); - xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart; - } else { - // Aligning with the drag handle. - int shortcutDragHandleWidth = resources.getDimensionPixelSize( - R.dimen.deep_shortcut_drag_handle_size); - int shortcutPaddingEnd = resources.getDimensionPixelSize( - R.dimen.popup_padding_end); - xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd; - } - x += mIsLeftAligned ? xOffset : -xOffset; - - // Open above icon if there is room. - int iconHeight = getIconHeightForPopupPlacement(); - int y = mTempRect.top + mOriginalIcon.getPaddingTop() - height; - mIsAboveIcon = y > dragLayer.getTop() + insets.top; - if (!mIsAboveIcon) { - y = mTempRect.top + mOriginalIcon.getPaddingTop() + iconHeight + extraVerticalSpace; - } - - // Insets are added later, so subtract them now. - if (mIsRtl) { - x += insets.right; - } else { - x -= insets.left; - } - y -= insets.top; - - mGravity = 0; - if (y + height > dragLayer.getBottom() - insets.bottom) { - // The container is opening off the screen, so just center it in the drag layer instead. - mGravity = Gravity.CENTER_VERTICAL; - // Put the container next to the icon, preferring the right side in ltr (left in rtl). - int rightSide = leftAlignedX + iconWidth - insets.left; - int leftSide = rightAlignedX - iconWidth - insets.left; - if (!mIsRtl) { - if (rightSide + width < dragLayer.getRight()) { - x = rightSide; - mIsLeftAligned = true; - } else { - x = leftSide; - mIsLeftAligned = false; - } - } else { - if (leftSide > dragLayer.getLeft()) { - x = leftSide; - mIsLeftAligned = false; - } else { - x = rightSide; - mIsLeftAligned = true; - } - } - mIsAboveIcon = true; - } - - setX(x); - if (Gravity.isVertical(mGravity)) { - return; - } - - DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); - DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams(); - if (mIsAboveIcon) { - arrowLp.gravity = lp.gravity = Gravity.BOTTOM; - lp.bottomMargin = - mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top; - arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom; - } else { - arrowLp.gravity = lp.gravity = Gravity.TOP; - lp.topMargin = y + insets.top; - arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset; - } - } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - - // enforce contained is within screen - DragLayer dragLayer = mLauncher.getDragLayer(); - if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) { - // If we are still off screen, center horizontally too. - mGravity |= Gravity.CENTER_HORIZONTAL; - } - - if (Gravity.isHorizontal(mGravity)) { - setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2); - mArrow.setVisibility(INVISIBLE); - } - if (Gravity.isVertical(mGravity)) { - setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2); - } - } - - protected void animateOpen() { - setVisibility(View.VISIBLE); - mIsOpen = true; - - final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet(); - final Resources res = getResources(); - final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration); - final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator(); - - // Rectangular reveal. - final ValueAnimator revealAnim = createOpenCloseOutlineProvider() - .createRevealAnimator(this, false); - revealAnim.setDuration(revealDuration); - revealAnim.setInterpolator(revealInterpolator); - - Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1); - fadeIn.setDuration(revealDuration); - fadeIn.setInterpolator(revealInterpolator); - openAnim.play(fadeIn); - - // Animate the arrow. - mArrow.setScaleX(0); - mArrow.setScaleY(0); - Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1) - .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration)); - - openAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mOpenCloseAnimator = null; - sendCustomAccessibilityEvent( - PopupContainerWithArrow.this, - AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, - getContext().getString(R.string.action_deep_shortcut)); - } - }); - - mOpenCloseAnimator = openAnim; - openAnim.playSequentially(revealAnim, arrowScale); - openAnim.start(); + protected void getTargetObjectLocation(Rect outPos) { + mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos); + outPos.top += mOriginalIcon.getPaddingTop(); + outPos.left += mOriginalIcon.getPaddingLeft(); + outPos.right -= mOriginalIcon.getPaddingRight(); + outPos.bottom = outPos.top + (mOriginalIcon.getIcon() != null + ? mOriginalIcon.getIcon().getBounds().height() + : mOriginalIcon.getHeight()); } public void applyNotificationInfos(List notificationInfos) { @@ -642,10 +351,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra if (onClickListener != null && widgetsView == null) { // We didn't have any widgets cached but now there are some, so enable the shortcut. if (mSystemShortcutContainer != this) { - View view = mInflater.inflate(R.layout.system_shortcut_icon_only, - mSystemShortcutContainer, false); - mSystemShortcutContainer.addView(view); - initializeSystemShortcut(view, widgetInfo); + initializeSystemShortcut( + R.layout.system_shortcut_icon_only, mSystemShortcutContainer, widgetInfo); } else { // If using the expanded system shortcut (as opposed to just the icon), we need to // reopen the container to ensure measurements etc. all work out. While this could @@ -665,7 +372,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } } - private void initializeSystemShortcut(View view, SystemShortcut info) { + private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) { + View view = inflateAndAdd(resId, container); if (view instanceof DeepShortcutView) { // Expanded system shortcut, with both icon and text shown on white background. final DeepShortcutView shortcutView = (DeepShortcutView) view; @@ -682,12 +390,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra (ItemInfo) mOriginalIcon.getTag())); } - protected int getIconHeightForPopupPlacement() { - return mOriginalIcon.getIcon() != null - ? mOriginalIcon.getIcon().getBounds().height() - : mOriginalIcon.getHeight(); - } - /** * Determines when the deferred drag should be started. * @@ -807,91 +509,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra targetParent.containerType = ContainerType.DEEPSHORTCUTS; } - protected void animateClose() { - if (!mIsOpen) { - return; - } - mEndRect.setEmpty(); - if (getOutlineProvider() instanceof RevealOutlineAnimation) { - ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect); - } - if (mOpenCloseAnimator != null) { - mOpenCloseAnimator.cancel(); - } - mIsOpen = false; - - final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet(); - // Hide the arrow - closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0)); - closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0)); - + @Override + protected void onCreateCloseAnimation(AnimatorSet anim) { // Animate original icon's text back in. - closeAnim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */)); + anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */)); mOriginalIcon.forceHideBadge(false); - - final Resources res = getResources(); - final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator(); - - // Rectangular reveal (reversed). - final ValueAnimator revealAnim = createOpenCloseOutlineProvider() - .createRevealAnimator(this, true); - revealAnim.setInterpolator(revealInterpolator); - closeAnim.play(revealAnim); - - Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0); - fadeOut.setInterpolator(revealInterpolator); - closeAnim.play(fadeOut); - closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration)); - - closeAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mOpenCloseAnimator = null; - if (mDeferContainerRemoval) { - setVisibility(INVISIBLE); - } else { - closeComplete(); - } - } - }); - mOpenCloseAnimator = closeAnim; - closeAnim.start(); - } - - private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() { - int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ? - R.dimen.popup_arrow_horizontal_center_start: - R.dimen.popup_arrow_horizontal_center_end); - if (!mIsLeftAligned) { - arrowCenterX = getMeasuredWidth() - arrowCenterX; - } - int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0; - - mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY); - if (mEndRect.isEmpty()) { - mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - } - - return new RoundedRectRevealOutlineProvider - (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect); - } - - /** - * Closes the popup without animation. - */ - private void closeComplete() { - mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); - mOriginalIcon.forceHideBadge(false); - - mLauncher.getDragController().removeDragListener(this); - if (mOpenCloseAnimator != null) { - mOpenCloseAnimator.cancel(); - mOpenCloseAnimator = null; - } - mIsOpen = false; - mDeferContainerRemoval = false; - mLauncher.getDragLayer().removeView(this); - mLauncher.getDragLayer().removeView(mArrow); } @Override diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java index 2f9cf3aab6..23f55aa17e 100644 --- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java +++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java @@ -144,7 +144,7 @@ public class WorkspaceTouchListener implements OnTouchListener, Runnable { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, Action.Direction.NONE, ContainerType.WORKSPACE, mWorkspace.getCurrentPage()); - OptionsPopupView.show(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y); + OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y); } } } diff --git a/src/com/android/launcher3/views/LauncherDragIndicator.java b/src/com/android/launcher3/views/LauncherDragIndicator.java index f15129cf48..986e4bee31 100644 --- a/src/com/android/launcher3/views/LauncherDragIndicator.java +++ b/src/com/android/launcher3/views/LauncherDragIndicator.java @@ -108,15 +108,12 @@ public class LauncherDragIndicator extends ImageView implements Insettable, OnCl @Override public boolean performAccessibilityAction(int action, Bundle arguments) { - Launcher launcher = Launcher.getLauncher(getContext()); if (action == WALLPAPERS) { - launcher.onClickWallpaperPicker(this); - return true; + return OptionsPopupView.startWallpaperPicker(this); } else if (action == WIDGETS) { - return OptionsPopupView.onWidgetsClicked(launcher); + return OptionsPopupView.onWidgetsClicked(this); } else if (action == SETTINGS) { - OptionsPopupView.startSettings(launcher); - return true; + return OptionsPopupView.startSettings(this); } return super.performAccessibilityAction(action, arguments); } diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 709a7e5c8b..56b92c7c62 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -15,52 +15,42 @@ */ package com.android.launcher3.views; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; +import static com.android.launcher3.BaseDraggingActivity.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION; +import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET; + import android.content.Context; import android.content.Intent; -import android.graphics.Outline; -import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; +import android.text.TextUtils; +import android.util.ArrayMap; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; -import android.view.ViewGroup; -import android.view.ViewOutlineProvider; import android.widget.Toast; -import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.anim.RevealOutlineAnimation; -import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; -import com.android.launcher3.dragndrop.DragLayer; -import com.android.launcher3.graphics.ColorScrim; +import com.android.launcher3.popup.ArrowPopup; +import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.widget.WidgetsFullSheet; +import java.util.ArrayList; +import java.util.List; + /** * Popup shown on long pressing an empty space in launcher */ -public class OptionsPopupView extends AbstractFloatingView +public class OptionsPopupView extends ArrowPopup implements OnClickListener, OnLongClickListener { - private final float mOutlineRadius; - private final Launcher mLauncher; - private final PointF mTouchPoint = new PointF(); - - private final ColorScrim mScrim; - - protected Animator mOpenCloseAnimator; + private final ArrayMap mItemMap = new ArrayMap<>(); + private RectF mTargetRect; public OptionsPopupView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -68,31 +58,6 @@ public class OptionsPopupView extends AbstractFloatingView public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - - mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius); - setClipToOutline(true); - setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius); - } - }); - - mLauncher = Launcher.getLauncher(context); - mScrim = ColorScrim.createExtractedColorScrim(this); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - attachListeners(findViewById(R.id.wallpaper_button)); - attachListeners(findViewById(R.id.widget_button)); - attachListeners(findViewById(R.id.settings_button)); - } - - private void attachListeners(View view) { - view.setOnClickListener(this); - view.setOnLongClickListener(this); } @Override @@ -106,20 +71,14 @@ public class OptionsPopupView extends AbstractFloatingView } private boolean handleViewClick(View view, int action) { - if (view.getId() == R.id.wallpaper_button) { - mLauncher.onClickWallpaperPicker(view); - logTap(action, ControlType.WALLPAPER_BUTTON); - close(true); - return true; - } else if (view.getId() == R.id.widget_button) { - logTap(action, ControlType.WIDGETS_BUTTON); - if (onWidgetsClicked(mLauncher)) { - close(true); - return true; - } - } else if (view.getId() == R.id.settings_button) { - startSettings(mLauncher); - logTap(action, ControlType.SETTINGS_BUTTON); + OptionItem item = mItemMap.get(view); + if (item == null) { + return false; + } + if (item.mControlTypeForLog > 0) { + logTap(action, item.mControlTypeForLog); + } + if (item.mClickListener.onLongClick(view)) { close(true); return true; } @@ -142,63 +101,6 @@ public class OptionsPopupView extends AbstractFloatingView return true; } - @Override - protected void handleClose(boolean animate) { - if (animate) { - animateClose(); - } else { - closeComplete(); - } - } - - protected void animateClose() { - if (!mIsOpen) { - return; - } - mIsOpen = false; - - final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet(); - closeAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration)); - - // Rectangular reveal (reversed). - final ValueAnimator revealAnim = createOpenCloseOutlineProvider() - .createRevealAnimator(this, true); - closeAnim.play(revealAnim); - - Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0); - fadeOut.setInterpolator(Interpolators.DEACCEL); - closeAnim.play(fadeOut); - - Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0); - gradientAlpha.setInterpolator(Interpolators.DEACCEL); - closeAnim.play(gradientAlpha); - - closeAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mOpenCloseAnimator = null; - closeComplete(); - } - }); - if (mOpenCloseAnimator != null) { - mOpenCloseAnimator.cancel(); - } - mOpenCloseAnimator = closeAnim; - closeAnim.start(); - } - - /** - * Closes the popup without animation. - */ - private void closeComplete() { - if (mOpenCloseAnimator != null) { - mOpenCloseAnimator.cancel(); - mOpenCloseAnimator = null; - } - mIsOpen = false; - mLauncher.getDragLayer().removeView(this); - } - @Override public void logActionCommand(int command) { // TODO: @@ -209,90 +111,49 @@ public class OptionsPopupView extends AbstractFloatingView return (type & TYPE_OPTIONS_POPUP) != 0; } - private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() { - DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); - Rect startRect = new Rect(); - startRect.offset((int) (mTouchPoint.x - lp.x), (int) (mTouchPoint.y - lp.y)); - - Rect endRect = new Rect(0, 0, lp.width, lp.height); - if (getOutlineProvider() instanceof RevealOutlineAnimation) { - ((RevealOutlineAnimation) getOutlineProvider()).getOutline(endRect); - } - - return new RoundedRectRevealOutlineProvider - (mOutlineRadius, mOutlineRadius, startRect, endRect); + @Override + protected void getTargetObjectLocation(Rect outPos) { + mTargetRect.roundOut(outPos); } - private void animateOpen() { - mIsOpen = true; - final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet(); - openAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration)); + public static void show(Launcher launcher, RectF targetRect, List items) { + OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater() + .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false); + popup.mTargetRect = targetRect; - final ValueAnimator revealAnim = createOpenCloseOutlineProvider() - .createRevealAnimator(this, false); - openAnim.play(revealAnim); - - Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1); - gradientAlpha.setInterpolator(Interpolators.ACCEL); - openAnim.play(gradientAlpha); - - mOpenCloseAnimator = openAnim; - - openAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mOpenCloseAnimator = null; - } - }); - openAnim.start(); + for (OptionItem item : items) { + DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup); + view.getIconView().setBackgroundResource(item.mIconRes); + view.getBubbleText().setText(item.mLabelRes); + view.setDividerVisibility(View.INVISIBLE); + view.setOnClickListener(popup); + view.setOnLongClickListener(popup); + popup.mItemMap.put(view, item); + } + popup.reorderAndShow(popup.getChildCount()); } - public static void show(Launcher launcher, float x, float y) { - DragLayer dl = launcher.getDragLayer(); - OptionsPopupView view = (OptionsPopupView) launcher.getLayoutInflater() - .inflate(R.layout.longpress_options_menu, dl, false); - DragLayer.LayoutParams lp = (DragLayer.LayoutParams) view.getLayoutParams(); - - int maxWidth = dl.getWidth(); - int maxHeight = dl.getHeight(); - if (x <= 0 || y <= 0 || x >= maxWidth || y >= maxHeight) { - x = maxWidth / 2; - y = maxHeight / 2; + public static void showDefaultOptions(Launcher launcher, float x, float y) { + float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2; + if (x < 0 || y < 0) { + x = launcher.getDragLayer().getWidth() / 2; + y = launcher.getDragLayer().getHeight() / 2; } - view.mTouchPoint.set(x, y); + RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize); - int height = lp.height; + ArrayList options = new ArrayList<>(); + options.add(new OptionItem(R.string.wallpaper_button_text, R.drawable.ic_wallpaper, + ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker)); + options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget, + ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked)); + options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting, + ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings)); - // Find a good width; - int childCount = view.getChildCount(); - int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); - int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth / childCount, MeasureSpec.AT_MOST); - int maxChildWidth = 0; - - for (int i = 0; i < childCount; i ++) { - View child = ((ViewGroup) view.getChildAt(i)).getChildAt(0); - child.measure(widthSpec, heightSpec); - maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth()); - } - Rect insets = dl.getInsets(); - int margin = (int) (2 * view.getElevation()); - - int width = Math.min(maxWidth - insets.left - insets.right - 2 * margin, - maxChildWidth * childCount); - lp.width = width; - - // Position is towards the finger - lp.customPosition = true; - lp.x = Utilities.boundToRange((int) (x - width / 2), insets.left + margin, - maxWidth - insets.right - width - margin); - lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin, - maxHeight - insets.bottom - height - margin); - - view.animateOpen(); - launcher.getDragLayer().addView(view); + show(launcher, target, options); } - public static boolean onWidgetsClicked(Launcher launcher) { + public static boolean onWidgetsClicked(View view) { + Launcher launcher = Launcher.getLauncher(view.getContext()); if (launcher.getPackageManager().isSafeMode()) { Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show(); return false; @@ -302,9 +163,51 @@ public class OptionsPopupView extends AbstractFloatingView } } - public static void startSettings(Launcher launcher) { + public static boolean startSettings(View view) { + Launcher launcher = Launcher.getLauncher(view.getContext()); launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES) .setPackage(launcher.getPackageName()) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + return true; + } + + /** + * Event handler for the wallpaper picker button that appears after a long press + * on the home screen. + */ + public static boolean startWallpaperPicker(View v) { + Launcher launcher = Launcher.getLauncher(v.getContext()); + if (!Utilities.isWallpaperAllowed(launcher)) { + Toast.makeText(launcher, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show(); + return false; + } + Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER) + .putExtra(EXTRA_WALLPAPER_OFFSET, + launcher.getWorkspace().getWallpaperOffsetForCenterPage()); + + String pickerPackage = launcher.getString(R.string.wallpaper_picker_package); + if (!TextUtils.isEmpty(pickerPackage)) { + intent.setPackage(pickerPackage); + } else { + // If there is no target package, use the default intent chooser animation + intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true); + } + return launcher.startActivitySafely(v, intent, null); + } + + public static class OptionItem { + + private final int mLabelRes; + private final int mIconRes; + private final int mControlTypeForLog; + private final OnLongClickListener mClickListener; + + public OptionItem(int labelRes, int iconRes, int controlTypeForLog, + OnLongClickListener clickListener) { + mLabelRes = labelRes; + mIconRes = iconRes; + mControlTypeForLog = controlTypeForLog; + mClickListener = clickListener; + } } } From ba406e2a449b1716e57249e24b65a05932e5b103 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 2 Apr 2018 11:36:12 -0700 Subject: [PATCH 38/81] Adding support for highlighting preference in sub-screens Change-Id: I1d5c0a7457a31755951b2f6be70a61a2d84463cf --- res/layout/launcher_preference.xml | 27 ----- .../android/launcher3/SettingsActivity.java | 56 +++++++-- .../ListViewHighlighter.java} | 113 +++++++++--------- 3 files changed, 101 insertions(+), 95 deletions(-) delete mode 100644 res/layout/launcher_preference.xml rename src/com/android/launcher3/{views/HighlightableListView.java => util/ListViewHighlighter.java} (55%) diff --git a/res/layout/launcher_preference.xml b/res/layout/launcher_preference.xml deleted file mode 100644 index ed0ea7c0e2..0000000000 --- a/res/layout/launcher_preference.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java index 7fa0e52259..c9bd32b086 100644 --- a/src/com/android/launcher3/SettingsActivity.java +++ b/src/com/android/launcher3/SettingsActivity.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -26,22 +27,25 @@ import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; import android.provider.Settings; import android.text.TextUtils; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.Adapter; +import android.widget.ListView; import com.android.launcher3.graphics.IconShapeOverride; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.util.ListViewHighlighter; import com.android.launcher3.util.SettingsObserver; import com.android.launcher3.views.ButtonPreference; -import com.android.launcher3.views.HighlightableListView; + +import java.util.Objects; /** * Settings activity for Launcher. Currently implements the following setting: Allow rotation @@ -84,12 +88,6 @@ public class SettingsActivity extends Activity { private String mPreferenceKey; private boolean mPreferenceHighlighted = false; - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.launcher_preference, container, false); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -145,12 +143,25 @@ public class SettingsActivity extends Activity { } private void highlightPreference() { - HighlightableListView list = getView().findViewById(android.R.id.list); Preference pref = findPreference(mPreferenceKey); - Adapter adapter = list.getAdapter(); - if (adapter == null) { + if (pref == null || getPreferenceScreen() == null) { return; } + PreferenceScreen screen = getPreferenceScreen(); + if (Utilities.ATLEAST_OREO) { + screen = selectPreferenceRecursive(pref, screen); + } + if (screen == null) { + return; + } + + View root = screen.getDialog() != null + ? screen.getDialog().getWindow().getDecorView() : getView(); + ListView list = root.findViewById(android.R.id.list); + if (list == null || list.getAdapter() == null) { + return; + } + Adapter adapter = list.getAdapter(); // Find the position int position = -1; @@ -160,7 +171,7 @@ public class SettingsActivity extends Activity { break; } } - list.highlightPosition(position); + new ListViewHighlighter(list, position); mPreferenceHighlighted = true; } @@ -172,6 +183,25 @@ public class SettingsActivity extends Activity { } super.onDestroy(); } + + @TargetApi(Build.VERSION_CODES.O) + private PreferenceScreen selectPreferenceRecursive( + Preference pref, PreferenceScreen topParent) { + if (!(pref.getParent() instanceof PreferenceScreen)) { + return null; + } + + PreferenceScreen parent = (PreferenceScreen) pref.getParent(); + if (Objects.equals(parent.getKey(), topParent.getKey())) { + return parent; + } else if (selectPreferenceRecursive(parent, topParent) != null) { + ((PreferenceScreen) parent.getParent()) + .onItemClick(null, null, parent.getOrder(), 0); + return parent; + } else { + return null; + } + } } /** diff --git a/src/com/android/launcher3/views/HighlightableListView.java b/src/com/android/launcher3/util/ListViewHighlighter.java similarity index 55% rename from src/com/android/launcher3/views/HighlightableListView.java rename to src/com/android/launcher3/util/ListViewHighlighter.java index 7da979fe14..ecad2afe2e 100644 --- a/src/com/android/launcher3/views/HighlightableListView.java +++ b/src/com/android/launcher3/util/ListViewHighlighter.java @@ -13,70 +13,92 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package com.android.launcher3.views; +package com.android.launcher3.util; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.support.v4.graphics.ColorUtils; -import android.util.AttributeSet; import android.view.View; -import android.view.ViewGroup; -import android.widget.HeaderViewListAdapter; -import android.widget.ListAdapter; +import android.view.View.OnLayoutChangeListener; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AbsListView.RecyclerListener; import android.widget.ListView; import com.android.launcher3.R; -import com.android.launcher3.util.Themes; - -import java.util.ArrayList; /** - * Extension of list view with support for element highlighting. + * Utility class to scroll and highlight a list view item */ -public class HighlightableListView extends ListView { +public class ListViewHighlighter implements OnScrollListener, RecyclerListener, + OnLayoutChangeListener { + + private final ListView mListView; + private int mPosHighlight; - private int mPosHighlight = -1; private boolean mColorAnimated = false; - public HighlightableListView(Context context) { - super(context); - } + public ListViewHighlighter(ListView listView, int posHighlight) { + mListView = listView; + mPosHighlight = posHighlight; + mListView.setOnScrollListener(this); + mListView.setRecyclerListener(this); + mListView.addOnLayoutChangeListener(this); - public HighlightableListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public HighlightableListView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + mListView.post(this::tryHighlight); } @Override - public void setAdapter(ListAdapter adapter) { - super.setAdapter(new HighLightAdapter(adapter)); + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + mListView.post(this::tryHighlight); } - public void highlightPosition(int pos) { - if (mPosHighlight == pos) { + private void tryHighlight() { + if (mPosHighlight < 0 || mListView.getChildCount() == 0) { return; } - - mColorAnimated = false; - mPosHighlight = pos; - setSelection(mPosHighlight); - - int start = getFirstVisiblePosition(); - int end = getLastVisiblePosition(); - if (start <= mPosHighlight && mPosHighlight <= end) { - highlightView(getChildAt(mPosHighlight - start)); + if (!highlightIfVisible(mListView.getFirstVisiblePosition(), + mListView.getLastVisiblePosition())) { + mListView.smoothScrollToPosition(mPosHighlight); } } + @Override + public void onScrollStateChanged(AbsListView absListView, int i) { } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + highlightIfVisible(firstVisibleItem, firstVisibleItem + visibleItemCount); + } + + private boolean highlightIfVisible(int start, int end) { + if (mPosHighlight < 0 || mListView.getChildCount() == 0) { + return false; + } + if (start > mPosHighlight || mPosHighlight > end) { + return false; + } + highlightView(mListView.getChildAt(mPosHighlight - start)); + + // finish highlight + mListView.setOnScrollListener(null); + mListView.removeOnLayoutChangeListener(this); + + mPosHighlight = -1; + return true; + } + + @Override + public void onMovedToScrapHeap(View view) { + unhighlightView(view); + } + private void highlightView(View view) { if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) { // already highlighted @@ -85,7 +107,6 @@ public class HighlightableListView extends ListView { view.setTag(R.id.view_unhighlight_background, view.getBackground()); view.setBackground(getHighlightBackground()); view.postDelayed(() -> { - mPosHighlight = -1; unhighlightView(view); }, 15000L); } @@ -102,26 +123,8 @@ public class HighlightableListView extends ListView { } } - private class HighLightAdapter extends HeaderViewListAdapter { - public HighLightAdapter(ListAdapter adapter) { - super(new ArrayList<>(), new ArrayList<>(), adapter); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View view = super.getView(position, convertView, parent); - - if (position == mPosHighlight) { - highlightView(view); - } else { - unhighlightView(view); - } - return view; - } - } - private ColorDrawable getHighlightBackground() { - int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(getContext()), 26); + int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(mListView.getContext()), 26); if (mColorAnimated) { return new ColorDrawable(color); } From 0f5b12c3d3b6fad5feaa473a2ea95f5d65dae763 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Thu, 29 Mar 2018 18:28:36 -0700 Subject: [PATCH 39/81] Mask work app snapshots in QuickStep when work profile is locked. Change-Id: I15b03a98d5f359a3b8ce28893fa183bb6af1d7d1 Fixes: 72807386 Test: manual test --- .../android/quickstep/views/TaskThumbnailView.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 4c8d69f684..8b41b58f38 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -54,6 +54,7 @@ public class TaskThumbnailView extends View { private final TaskOverlay mOverlay; private final Paint mPaint = new Paint(); + private final Paint mLockedPaint = new Paint(); private final Matrix mMatrix = new Matrix(); @@ -77,6 +78,7 @@ public class TaskThumbnailView extends View { mFadeLength = getResources().getDimension(R.dimen.task_fade_length); mOverlay = TaskOverlayFactory.get(context).createOverlay(this); mPaint.setFilterBitmap(true); + mLockedPaint.setColor(Color.WHITE); } public void bind() { @@ -123,14 +125,19 @@ public class TaskThumbnailView extends View { @Override protected void onDraw(Canvas canvas) { - canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), - mCornerRadius, mCornerRadius, mPaint); + if (mTask == null) { + return; + } + canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius, + mCornerRadius, mTask.isLocked ? mLockedPaint : mPaint); } private void updateThumbnailPaintFilter() { int mul = (int) (mDimAlpha * 255); if (mBitmapShader != null) { - mPaint.setColorFilter(getLightingColorFilter(mul)); + LightingColorFilter filter = getLightingColorFilter(mul); + mPaint.setColorFilter(filter); + mLockedPaint.setColorFilter(filter); } else { mPaint.setColorFilter(null); mPaint.setColor(Color.argb(255, mul, mul, mul)); From 1c6d5668706c207cc49eec85d30c3ab411d557c9 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 2 Apr 2018 15:27:28 -0700 Subject: [PATCH 40/81] Ensuring that previous animation is completed before starting a new state animation Bug: 76231621 Bug: 77150113 Change-Id: I086e8063b08d2ba69ead1bd0ee1772d65fb6075c --- .../LauncherAppTransitionManagerImpl.java | 62 ++++++++----------- .../launcher3/LauncherStateManager.java | 4 ++ 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 8f2e104dab..e4a8f36497 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -146,15 +146,18 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats); AnimatorSet anim = new AnimatorSet(); - if (anims != null) { - anim.playTogether(anims); - } else { - anim.play(getLauncherAnimators(v, targetCompats)); + // Set the state animation first so that any state listeners are called + // before our internal listeners. + mLauncher.getStateManager().setCurrentAnimation(anim); + + if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) { + if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) { + anim.play(getIconAnimator(v)); + anim.play(getLauncherContentAnimator(false /* show */)); + } anim.play(getWindowAnimators(v, targetCompats)); } - mLauncher.getStateManager().setCurrentAnimation(anim); return anim; } }; @@ -233,11 +236,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag /** * Composes the animations for a launch from the recents list if possible. */ - private Animator[] composeRecentsLaunchAnimator(View v, - RemoteAnimationTargetCompat[] targets) { + private boolean composeRecentsLaunchAnimator(View v, + RemoteAnimationTargetCompat[] targets, AnimatorSet target) { // Ensure recents is actually visible if (!mLauncher.getStateManager().getState().overviewUi) { - return null; + return false; } RecentsView recentsView = mLauncher.getOverviewPanel(); @@ -246,7 +249,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); if (taskView == null) { - return null; + return false; } // Found a visible recents task that matches the opening app, lets launch the app from there @@ -273,9 +276,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } - Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets); - windowAnim.addListener(windowAnimEndListener); - return new Animator[] {launcherAnim, windowAnim}; + target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets)); + target.play(launcherAnim); + target.addListener(windowAnimEndListener); + return true; } /** @@ -354,18 +358,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return appAnimator; } - /** - * @return Animators that control the movements of the Launcher and icon of the opening target. - */ - private AnimatorSet getLauncherAnimators(View v, RemoteAnimationTargetCompat[] targets) { - AnimatorSet launcherAnimators = new AnimatorSet(); - launcherAnimators.play(getIconAnimator(v)); - if (launcherIsATargetWithMode(targets, MODE_CLOSING)) { - launcherAnimators.play(getLauncherContentAnimator(false /* show */)); - } - return launcherAnimators; - } - /** * Content is everything on screen except the background and the floating view (if any). * @@ -687,11 +679,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag anim.play(getClosingWindowAnimators(targetCompats)); if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) { - AnimatorSet contentAnimation = getLauncherResumeAnimation(); - anim.play(contentAnimation); - // Only register the content animation for cancellation when state changes - mLauncher.getStateManager().setCurrentAnimation(contentAnimation); + mLauncher.getStateManager().setCurrentAnimation(anim); + createLauncherResumeAnimation(anim); } return anim; } @@ -754,14 +744,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } /** - * @return Animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}. + * Creates an animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}. */ - private AnimatorSet getLauncherResumeAnimation() { + private void createLauncherResumeAnimation(AnimatorSet anim) { if (mLauncher.isInState(LauncherState.ALL_APPS) || mLauncher.getDeviceProfile().isVerticalBarLayout()) { AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */); contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY); - return contentAnimator; + anim.play(contentAnimator); } else { AnimatorSet workspaceAnimator = new AnimatorSet(); @@ -799,12 +789,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag allAppsOvershoot.setDuration(153); allAppsOvershoot.setInterpolator(Interpolators.OVERSHOOT_0); - AnimatorSet resumeLauncherAnimation = new AnimatorSet(); - resumeLauncherAnimation.play(workspaceAnimator); - resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot); - resumeLauncherAnimation.addListener(mReapplyStateListener); - return resumeLauncherAnimation; + anim.play(workspaceAnimator); + anim.playSequentially(allAppsSlideIn, allAppsOvershoot); + anim.addListener(mReapplyStateListener); } } diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index ef285df6fa..534c8ae351 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -356,7 +356,11 @@ public class LauncherStateManager { * starting another animation and may block some launcher interactions while running. */ public void setCurrentAnimation(AnimatorSet anim) { + boolean reapplyNeeded = mConfig.mCurrentAnimation != null; cancelAnimation(); + if (reapplyNeeded) { + reapplyState(); + } mConfig.setAnimation(anim); } From cd7690d789115f701fce10284ec37afbd825e578 Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Mon, 2 Apr 2018 15:52:04 -0700 Subject: [PATCH 41/81] Do not show overview when deviced has pinned Prevents launching overview when recents button is pressed while pinning an app. This only occurs if quick step is disabled. Test: disable quickstep, pin an app and try to go to overview Change-Id: I0d453c2b6f6ebc7947de670b6cf5d09705f9188e Fixes: 76702534 --- .../src/com/android/quickstep/OverviewCommandHelper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 958feb7dbe..985a36490e 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -236,6 +236,11 @@ public class OverviewCommandHelper extends InternalStateHandler { } public void onOverviewToggle() { + // If currently screen pinning, do not enter overview + if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { + return; + } + long time = SystemClock.elapsedRealtime(); mMainThreadExecutor.execute(() -> { long elapsedTime = time - mLastToggleTime; From ab88b2243ddeaeff7203476b21bee92c4d9e6adb Mon Sep 17 00:00:00 2001 From: Mario Bertschler Date: Mon, 26 Mar 2018 18:29:17 +0200 Subject: [PATCH 42/81] Make drawDragView protected so it can be used in subclasses. Bug: 73818519 Bug: 74404893 Change-Id: I75b8cc322bd8d96be83adbfaf2c0244df27019d8 --- src/com/android/launcher3/graphics/DragPreviewProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index e60a2c70b1..5094280f6a 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -76,7 +76,7 @@ public class DragPreviewProvider { /** * Draws the {@link #mView} into the given {@param destCanvas}. */ - private void drawDragView(Canvas destCanvas, float scale) { + protected void drawDragView(Canvas destCanvas, float scale) { destCanvas.save(); destCanvas.scale(scale, scale); From 274b9529fff4df680069afbff51f294346c9f4f7 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 28 Mar 2018 11:21:49 -0700 Subject: [PATCH 43/81] Support swiping between states - Swiping down on hotseat from overview goes to workspace - Can swipe up through overview to get to all apps Bug: 76449024 Change-Id: I7f76d92da976e268cc2a97e55746cca4603e6620 --- .../LandscapeEdgeSwipeController.java | 8 ++- .../LandscapeStatesTouchController.java | 5 +- .../PortraitStatesTouchController.java | 23 ++++----- .../AbstractStateChangeTouchController.java | 49 +++++++++++++++---- .../uioverrides/AllAppsSwipeController.java | 10 ++-- 5 files changed, 65 insertions(+), 30 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java index 23add9595c..3622fc4250 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java @@ -37,11 +37,15 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro @Override protected int getSwipeDirection(MotionEvent ev) { - mFromState = NORMAL; - mToState = OVERVIEW; return SwipeDetector.DIRECTION_BOTH; } + @Override + protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive; + return draggingFromNav ? OVERVIEW : NORMAL; + } + @Override protected float getShiftRange() { return mLauncher.getDragLayer().getWidth(); diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java index 720b20ac1b..355b88d910 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java @@ -58,8 +58,9 @@ public class LandscapeStatesTouchController extends PortraitStatesTouchControlle } } - protected LauncherState getTargetState() { - if (mLauncher.isInState(ALL_APPS)) { + @Override + protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + if (fromState == ALL_APPS) { // Should swipe down go to OVERVIEW instead? return TouchInteractionService.isConnected() ? mLauncher.getStateManager().getLastState() : NORMAL; diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index 7d9cce49a2..bdbdd8f76e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -44,10 +44,10 @@ import com.android.quickstep.util.SysuiEventLogger; */ public class PortraitStatesTouchController extends AbstractStateChangeTouchController { - private static final float TOTAL_DISTANCE_MULTIPLIER = 2f; + private static final float TOTAL_DISTANCE_MULTIPLIER = 3f; private static final float LINEAR_SCALE_LIMIT = 1 / TOTAL_DISTANCE_MULTIPLIER; - // Much be greater than LINEAR_SCALE_LIMIT; + // Must be greater than LINEAR_SCALE_LIMIT; private static final float MAXIMUM_DISTANCE_FACTOR = 0.9f; // Maximum amount to overshoot. @@ -129,29 +129,26 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE; mStartContainerType = ContainerType.HOTSEAT; } else if (mLauncher.isInState(OVERVIEW)) { - directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE; + directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH; mStartContainerType = ContainerType.TASKSWITCHER; } else { return 0; } - mFromState = mLauncher.getStateManager().getState(); - mToState = getTargetState(); - if (mFromState == mToState) { - return 0; - } return directionsToDetectScroll; } - protected LauncherState getTargetState() { - if (mLauncher.isInState(ALL_APPS)) { + @Override + protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + if (fromState == ALL_APPS) { // Should swipe down go to OVERVIEW instead? return TouchInteractionService.isConnected() ? mLauncher.getStateManager().getLastState() : NORMAL; - } else if (mLauncher.isInState(OVERVIEW)) { - return ALL_APPS; - } else { + } else if (fromState == OVERVIEW) { + return isDragTowardPositive ? ALL_APPS : NORMAL; + } else if (isDragTowardPositive) { return TouchInteractionService.isConnected() ? OVERVIEW : ALL_APPS; } + return fromState; } private AnimatorSetBuilder getNormalToOverviewAnimation() { diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index a22f450e3b..4e905fa50a 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -19,7 +19,6 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.util.Log; import android.view.MotionEvent; @@ -58,6 +57,7 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene private float mStartProgress; // Ratio of transition process [0, 1] to drag displacement (px) private float mProgressMultiplier; + private float mDisplacementShift; public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) { mLauncher = l; @@ -68,7 +68,7 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene /** * Initializes the {@code mFromState} and {@code mToState} and swipe direction to use for - * the detector. In can of disabling swipe, return 0. + * the detector. In case of disabling swipe, return 0. */ protected abstract int getSwipeDirection(MotionEvent ev); @@ -122,16 +122,36 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene return mLauncher.getAllAppsController().getShiftRange(); } + protected abstract LauncherState getTargetState(LauncherState fromState, + boolean isDragTowardPositive); + protected abstract float initCurrentAnimation(); + private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) { + LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState() + : reachedToState ? mToState : mFromState; + LauncherState newToState = getTargetState(newFromState, isDragTowardPositive); + + if (newFromState == mFromState && newToState == mToState || (newFromState == newToState)) { + return false; + } + + mFromState = newFromState; + mToState = newToState; + + mStartProgress = 0; + mProgressMultiplier = initCurrentAnimation(); + mCurrentAnimation.getTarget().addListener(this); + mCurrentAnimation.dispatchOnStart(); + return true; + } + @Override public void onDragStart(boolean start) { if (mCurrentAnimation == null) { - mStartProgress = 0; - mProgressMultiplier = initCurrentAnimation(); - - mCurrentAnimation.getTarget().addListener(this); - mCurrentAnimation.dispatchOnStart(); + mFromState = mToState = null; + reinitCurrentAnimation(false, mDetector.wasInitialTouchPositive()); + mDisplacementShift = 0; } else { mCurrentAnimation.pause(); mStartProgress = mCurrentAnimation.getProgressFraction(); @@ -140,8 +160,19 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene @Override public boolean onDrag(float displacement, float velocity) { - float deltaProgress = mProgressMultiplier * displacement; - updateProgress(deltaProgress + mStartProgress); + float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift); + float progress = deltaProgress + mStartProgress; + updateProgress(progress); + boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0; + if (progress <= 0) { + if (reinitCurrentAnimation(false, isDragTowardPositive)) { + mDisplacementShift = displacement; + } + } else if (progress >= 1) { + if (reinitCurrentAnimation(true, isDragTowardPositive)) { + mDisplacementShift = displacement; + } + } return true; } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java index e495477f57..c97c3ccecb 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java @@ -7,6 +7,7 @@ import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -43,18 +44,19 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { protected int getSwipeDirection(MotionEvent ev) { if (mLauncher.isInState(ALL_APPS)) { mStartContainerType = ContainerType.ALLAPPS; - mFromState = ALL_APPS; - mToState = NORMAL; return SwipeDetector.DIRECTION_NEGATIVE; } else { - mFromState = NORMAL; - mToState = ALL_APPS; mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; return SwipeDetector.DIRECTION_POSITIVE; } } + @Override + protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + return fromState == ALL_APPS ? NORMAL : ALL_APPS; + } + @Override protected float initCurrentAnimation() { float range = getShiftRange(); From 1c6f12d11900f2b7462b09bf4ff9eba208b71417 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 2 Apr 2018 15:22:06 -0700 Subject: [PATCH 44/81] Swipe down on hotseat to launch recent task If you're ever in overview and swipe down on the hotseat, it will launch the focused task *unless* you entered overview from the workspace and have not scrolled past the first task. This is a hidden state to allow for reversibility of the swipe up from workspace. Also moved PendingAnimation from quickstep to launcher3. Change-Id: Iea077bc0ef7c74f6bf7b98d0a638892b9c5fe36c --- .../PortraitStatesTouchController.java | 23 +++++++++++++++++-- .../uioverrides/TaskViewTouchController.java | 2 +- .../launcher3/uioverrides/UiFactory.java | 15 ++++++++---- .../WindowTransformSwipeHandler.java | 2 ++ .../android/quickstep/views/RecentsView.java | 14 ++++++++++- src/com/android/launcher3/LauncherState.java | 1 - .../AbstractStateChangeTouchController.java | 13 ++++++++++- .../launcher3/util}/PendingAnimation.java | 2 +- 8 files changed, 61 insertions(+), 11 deletions(-) rename {quickstep/src/com/android/quickstep => src/com/android/launcher3/util}/PendingAnimation.java (97%) diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index bdbdd8f76e..0c34b45302 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -32,12 +32,16 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.Interpolators; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.util.SysuiEventLogger; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskView; /** * Touch controller for handling various state transitions in portrait UI. @@ -191,8 +195,23 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr mClampProgressUpdate = -1; } - mCurrentAnimation = mLauncher.getStateManager() - .createAnimationToNewWorkspace(mToState, builder, maxAccuracy); + if (mPendingAnimation != null) { + mPendingAnimation.finish(false); + mPendingAnimation = null; + } + + RecentsView recentsView = mLauncher.getOverviewPanel(); + TaskView taskView = (TaskView) recentsView.getChildAt(recentsView.getNextPage()); + if (recentsView.shouldSwipeDownLaunchApp() && mFromState == OVERVIEW && mToState == NORMAL + && taskView != null) { + mPendingAnimation = recentsView.createTaskLauncherAnimation(taskView, maxAccuracy); + mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN); + + mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation.anim, maxAccuracy); + } else { + mCurrentAnimation = mLauncher.getStateManager() + .createAnimationToNewWorkspace(mToState, builder, maxAccuracy); + } if (totalShift == 0) { totalShift = Math.signum(mFromState.ordinal - mToState.ordinal) diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index 7b2487ada8..e73b2197fb 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -34,7 +34,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.PendingAnimation; +import com.android.launcher3.util.PendingAnimation; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 3cae3718f3..c1590f63de 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -16,6 +16,7 @@ package com.android.launcher3.uioverrides; +import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.Utilities.getPrefs; import static com.android.quickstep.OverviewInteractionState.KEY_SWIPE_UP_ENABLED; @@ -25,7 +26,9 @@ import android.content.Context; import android.content.SharedPreferences; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; @@ -89,11 +92,15 @@ public class UiFactory { } public static void onLauncherStateOrResumeChanged(Launcher launcher) { + LauncherState state = launcher.getStateManager().getState(); + DeviceProfile profile = launcher.getDeviceProfile(); WindowManagerWrapper.getInstance().setShelfHeight( - launcher.getStateManager().getState() != ALL_APPS && - launcher.isUserActive() && - !launcher.getDeviceProfile().isVerticalBarLayout(), - launcher.getDeviceProfile().hotseatBarSizePx); + state != ALL_APPS && launcher.isUserActive() && !profile.isVerticalBarLayout(), + profile.hotseatBarSizePx); + + if (state == NORMAL) { + launcher.getOverviewPanel().setSwipeDownShouldLaunchApp(false); + } } public static void onTrimMemory(Context context, int level) { diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 33f13100ce..611f7e0156 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -762,6 +762,8 @@ public class WindowTransformSwipeHandler { // Animate the first icon. mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */); + mRecentsView.setSwipeDownShouldLaunchApp(true); + reset(); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 50a32e64bc..e7f69b7b38 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -60,7 +60,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Themes; -import com.android.quickstep.PendingAnimation; +import com.android.launcher3.util.PendingAnimation; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; @@ -139,6 +139,7 @@ public abstract class RecentsView private boolean mOverviewStateEnabled; private boolean mTaskStackListenerRegistered; private Runnable mNextPageSwitchRunnable; + private boolean mSwipeDownShouldLaunchApp; private PendingAnimation mPendingAnimation; @@ -275,6 +276,9 @@ public abstract class RecentsView mNextPageSwitchRunnable.run(); mNextPageSwitchRunnable = null; } + if (getNextPage() > 0) { + setSwipeDownShouldLaunchApp(true); + } } @Override @@ -601,6 +605,14 @@ public abstract class RecentsView } } + public void setSwipeDownShouldLaunchApp(boolean swipeDownShouldLaunchApp) { + mSwipeDownShouldLaunchApp = swipeDownShouldLaunchApp; + } + + public boolean shouldSwipeDownLaunchApp() { + return mSwipeDownShouldLaunchApp; + } + public interface PageCallbacks { /** diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 21f9d5acaa..fdb6f482ad 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -18,7 +18,6 @@ package com.android.launcher3; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; - import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.states.RotationHelper.REQUEST_NONE; diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 4e905fa50a..9726704ddb 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -30,6 +30,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.TouchController; +import com.android.launcher3.util.PendingAnimation; /** * TouchController for handling state changes @@ -53,6 +54,7 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene protected LauncherState mFromState; protected LauncherState mToState; protected AnimatorPlaybackController mCurrentAnimation; + protected PendingAnimation mPendingAnimation; private float mStartProgress; // Ratio of transition process [0, 1] to drag displacement (px) @@ -254,7 +256,16 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene mLauncher.getWorkspace().getCurrentPage()); } clearState(); - mLauncher.getStateManager().goToState(targetState, false /* animated */); + boolean shouldGoToTargetState = true; + if (mPendingAnimation != null) { + boolean reachedTarget = mToState == targetState; + mPendingAnimation.finish(reachedTarget); + mPendingAnimation = null; + shouldGoToTargetState = !reachedTarget; + } + if (shouldGoToTargetState) { + mLauncher.getStateManager().goToState(targetState, false /* animated */); + } } protected void clearState() { diff --git a/quickstep/src/com/android/quickstep/PendingAnimation.java b/src/com/android/launcher3/util/PendingAnimation.java similarity index 97% rename from quickstep/src/com/android/quickstep/PendingAnimation.java rename to src/com/android/launcher3/util/PendingAnimation.java index d22ef61053..4116d56e1d 100644 --- a/quickstep/src/com/android/quickstep/PendingAnimation.java +++ b/src/com/android/launcher3/util/PendingAnimation.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep; +package com.android.launcher3.util; import android.animation.AnimatorSet; import android.annotation.TargetApi; From 2b67bacadcd2daa7c9f01fda37827c0e1dd8e972 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 3 Apr 2018 11:54:49 -0700 Subject: [PATCH 45/81] Fix bug where drag handle translation was not set to 0 on device profile change. Bug: 77523779 Change-Id: Idec97c34999e05adfac7e9931ab9596a8aae67ae --- .../android/launcher3/allapps/AllAppsTransitionController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 8788db4454..ed9873eaf6 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -99,6 +99,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil mAppsView.setAlpha(1); mLauncher.getHotseat().setTranslationY(0); mLauncher.getWorkspace().getPageIndicator().setTranslationY(0); + mLauncher.getDragHandleIndicator().setTranslationY(0); } } From d2e3c5de56b811448cab6a38893e63f74bb0b799 Mon Sep 17 00:00:00 2001 From: Mario Bertschler Date: Thu, 29 Mar 2018 21:12:12 +0200 Subject: [PATCH 46/81] Adding WEB_APP item type for logging. Set in LoggerUtils.newItemTarget if instant app Bug:67049361 Change-Id: I8e99e5c60bf1a2083f898e8978d403138f803276 --- protos/launcher_log.proto | 1 + .../launcher3/dragndrop/AddItemActivity.java | 5 ++++- .../android/launcher3/logging/LoggerUtils.java | 14 ++++++++++---- .../launcher3/logging/UserEventDispatcher.java | 17 +++++++++++------ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto index 3b983d254f..4013429b17 100644 --- a/protos/launcher_log.proto +++ b/protos/launcher_log.proto @@ -69,6 +69,7 @@ enum ItemType { EDITTEXT = 7; NOTIFICATION = 8; TASK = 9; // Each page of Recents UI (QuickStep) + WEB_APP = 10; } // Used to define what type of container a Target would represent. diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 95e1034365..278eefdd92 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -53,6 +53,7 @@ import com.android.launcher3.model.WidgetItem; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetHostViewLoader; @@ -82,6 +83,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener private Bundle mWidgetOptions; private boolean mFinishOnPause = false; + private InstantAppResolver mInstantAppResolver; @Override protected void onCreate(Bundle savedInstanceState) { @@ -95,6 +97,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener mApp = LauncherAppState.getInstance(this); mIdp = mApp.getInvariantDeviceProfile(); + mInstantAppResolver = InstantAppResolver.newInstance(this); // Use the application context to get the device profile, as in multiwindow-mode, the // confirmation activity might be rotated. @@ -298,7 +301,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener private void logCommand(int command) { getUserEventDispatcher().dispatchUserEvent(newLauncherEvent( newCommandAction(command), - newItemTarget(mWidgetCell.getWidgetView()), + newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver), newContainerTarget(ContainerType.PINITEM)), null); } } diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java index d68ac15966..01b1424a02 100644 --- a/src/com/android/launcher3/logging/LoggerUtils.java +++ b/src/com/android/launcher3/logging/LoggerUtils.java @@ -15,10 +15,12 @@ */ package com.android.launcher3.logging; +import android.content.Context; import android.util.ArrayMap; import android.util.SparseArray; import android.view.View; +import com.android.launcher3.AppInfo; import com.android.launcher3.ButtonDropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherSettings; @@ -29,6 +31,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.InstantAppResolver; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -127,18 +130,21 @@ public class LoggerUtils { return t; } - public static Target newItemTarget(View v) { + public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) { return (v.getTag() instanceof ItemInfo) - ? newItemTarget((ItemInfo) v.getTag()) + ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver) : newTarget(Target.Type.ITEM); } - public static Target newItemTarget(ItemInfo info) { + public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) { Target t = newTarget(Target.Type.ITEM); switch (info.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: - t.itemType = ItemType.APP_ICON; + t.itemType = (instantAppResolver != null && info instanceof AppInfo + && instantAppResolver.isInstantApp(((AppInfo) info)) ) + ? ItemType.WEB_APP + : ItemType.APP_ICON; t.predictedRank = -100; // Never assigned break; case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index 627115d878..90355bd67c 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -38,6 +38,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.LogConfig; import java.util.Locale; @@ -78,6 +79,7 @@ public class UserEventDispatcher { ued.mIsInLandscapeMode = dp.isVerticalBarLayout(); ued.mIsInMultiWindowMode = dp.isMultiWindowMode; ued.mUuidStr = uuidStr; + ued.mInstantAppResolver = InstantAppResolver.newInstance(context); return ued; } @@ -126,6 +128,7 @@ public class UserEventDispatcher { private boolean mIsInMultiWindowMode; private boolean mIsInLandscapeMode; private String mUuidStr; + protected InstantAppResolver mInstantAppResolver; // APP_ICON SHORTCUT WIDGET // -------------------------------------------------------------- @@ -151,7 +154,7 @@ public class UserEventDispatcher { public void logAppLaunch(View v, Intent intent) { LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP), - newItemTarget(v), newTarget(Target.Type.CONTAINER)); + newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); if (fillInLogContainerData(event, v)) { fillIntentInfo(event.srcTarget[0], intent); @@ -184,7 +187,7 @@ public class UserEventDispatcher { public void logNotificationLaunch(View v, PendingIntent intent) { LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP), - newItemTarget(v), newTarget(Target.Type.CONTAINER)); + newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); if (fillInLogContainerData(event, v)) { event.srcTarget[0].packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode(); } @@ -215,7 +218,7 @@ public class UserEventDispatcher { */ public void logActionCommand(int command, View itemView, int srcContainerType) { LauncherEvent event = newLauncherEvent(newCommandAction(command), - newItemTarget(itemView), newTarget(Target.Type.CONTAINER)); + newItemTarget(itemView, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); if (fillInLogContainerData(event, itemView)) { // TODO: Remove the following two lines once fillInLogContainerData can take in a @@ -320,7 +323,7 @@ public class UserEventDispatcher { } ItemInfo info = (ItemInfo) icon.getTag(); LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.LONGPRESS), - newItemTarget(info), newTarget(Target.Type.CONTAINER)); + newItemTarget(info, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); provider.fillInLogContainerData(icon, info, event.srcTarget[0], event.srcTarget[1]); dispatchUserEvent(event, null); @@ -338,9 +341,11 @@ public class UserEventDispatcher { public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) { LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP), - newItemTarget(dragObj.originalDragInfo), newTarget(Target.Type.CONTAINER)); + newItemTarget(dragObj.originalDragInfo, mInstantAppResolver), + newTarget(Target.Type.CONTAINER)); event.destTarget = new Target[] { - newItemTarget(dragObj.originalDragInfo), newDropTarget(dropTargetAsView) + newItemTarget(dragObj.originalDragInfo, mInstantAppResolver), + newDropTarget(dropTargetAsView) }; dragObj.dragSource.fillInLogContainerData(null, dragObj.originalDragInfo, From 9c5ece3eec7aa9790c4e851f2e1a7ba5d5c698dd Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 3 Apr 2018 11:54:50 -0700 Subject: [PATCH 47/81] Invoking onOverviewShown() on showRecents(false) If a CTS test wants to show Recents in split-screen mode, we call this and the test passes :) This is good enough for now. Bug: 77275679 Test: atest android.server.am.ActivityManagerSplitScreenTests#testDockedStackToMinimizeWhenUnlocked Change-Id: I5ac1b2890f70a48d86b7b0e85b6ebb8263843484 --- .../src/com/android/quickstep/TouchInteractionService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 1ded4dd0ec..b610f4d424 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -134,6 +134,8 @@ public class TouchInteractionService extends Service { if (triggeredFromAltTab) { setupTouchConsumer(HIT_TARGET_NONE); mEventQueue.onOverviewShownFromAltTab(); + } else { + mOverviewCommandHelper.onOverviewShown(); } } From 8ad31511a6f9c6ab63b8c97b53eb475566e109d3 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 28 Mar 2018 16:47:40 -0700 Subject: [PATCH 48/81] Update api for canceling recents animation. Bug: 74405472 Change-Id: Idb2fdec88115927a2db94e0216b1bea8386e6f23 --- .../src/com/android/quickstep/OtherActivityTouchConsumer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 4bd4a11b2a..0ab2df7e4c 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -285,7 +285,8 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC // Also clean up in case the system has handled the UP and canceled the animation before // we had a chance to start the recents animation. In such a case, we will not receive - ActivityManagerWrapper.getInstance().cancelRecentsAnimation(); + ActivityManagerWrapper.getInstance().cancelRecentsAnimation( + true /* restoreHomeStackPosition */); } mVelocityTracker.recycle(); mVelocityTracker = null; From dbff75e3dec3c4c3654a2c8bf4e7cd065ef0bef5 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 16 Mar 2018 12:10:55 -0700 Subject: [PATCH 49/81] Update dock divider during recents animation. - Move all wrapper calls to the bg thread - Account for position now that the task leash is in the app animation layer Bug: 73118672 Change-Id: I5b680a688c0ad4ca34c76e22e1d5cee24133f40f --- quickstep/libs/sysui_shared.jar | Bin 119143 -> 120112 bytes .../quickstep/RecentsAnimationWrapper.java | 42 +++++++++++++++++- .../WindowTransformSwipeHandler.java | 7 +-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index 2b9db35bc007f5e20e871b34321af7a01b7db2a0..3c5033e554a7484f00b66fccb69a495605b1d607 100644 GIT binary patch delta 10053 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 Z5Ka}E0vK=&5DXBK?;;>TpB~WK{vS~DV@d!3 delta 9195 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 Pa2Wq(7>un1EEM*Crs?ds diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java index 4e11220745..12f8d52b82 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java @@ -28,7 +28,9 @@ public class RecentsAnimationWrapper { public RecentsAnimationControllerCompat controller; public RemoteAnimationTargetCompat[] targets; - private boolean mInputConsumerEnabled; + private boolean mInputConsumerEnabled = false; + private boolean mBehindSystemBars = true; + private boolean mSplitScreenMinimized = false; public synchronized void setController( RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) { @@ -75,4 +77,42 @@ public class RecentsAnimationWrapper { }); } } + + public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { + if (mBehindSystemBars == behindSystemBars) { + return; + } + mBehindSystemBars = behindSystemBars; + BackgroundExecutor.get().submit(() -> { + synchronized (this) { + TraceHelper.partitionSection("RecentsController", + "Setting behind system bars on " + controller); + if (controller != null) { + controller.setAnimationTargetsBehindSystemBars(behindSystemBars); + } + } + }); + } + + /** + * NOTE: As a workaround for conflicting animations (Launcher animating the task leash, and + * SystemUI resizing the docked stack, which resizes the task), we currently only set the + * minimized mode, and not the inverse. + * TODO: Synchronize the minimize animation with the launcher animation + */ + public void setSplitScreenMinimizedForTransaction(boolean minimized) { + if (mSplitScreenMinimized || !minimized) { + return; + } + mSplitScreenMinimized = minimized; + BackgroundExecutor.get().submit(() -> { + synchronized (this) { + TraceHelper.partitionSection("RecentsController", + "Setting minimize dock on " + controller); + if (controller != null) { + controller.setSplitScreenMinimized(minimized); + } + } + }); + } } diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 611f7e0156..36a9d56496 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -497,6 +497,7 @@ public class WindowTransformSwipeHandler { TransactionCompat transaction = new TransactionCompat(); for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { if (app.mode == MODE_CLOSING) { + mTmpMatrix.postTranslate(app.position.x, app.position.y); transaction.setMatrix(app.leash, mTmpMatrix) .setWindowCrop(app.leash, mClipRect); @@ -534,10 +535,10 @@ public class WindowTransformSwipeHandler { } } if (mRecentsAnimationWrapper.controller != null) { - // TODO: This logic is spartanic! - mRecentsAnimationWrapper.controller.setAnimationTargetsBehindSystemBars( - shift < 0.12f); + boolean passedThreshold = shift > 0.12f; + mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold); + mRecentsAnimationWrapper.setSplitScreenMinimizedForTransaction(passedThreshold); } }; if (Looper.getMainLooper() == Looper.myLooper()) { From e6bbefb768263d3ed5ad19879a554bd1c84b136a Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 3 Apr 2018 13:38:06 -0700 Subject: [PATCH 50/81] Making task list carousel accessibility-scrollable No pane titles yet, as they are not yet reasonably supported by Talkback. Bug: 72409756 Test: Manual Change-Id: I3d2317b9180ac6b02977a4ee8212ae30f0533b2f --- src/com/android/launcher3/PagedView.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 1e761e41d4..79993c11aa 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -41,6 +41,7 @@ import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; +import android.widget.ScrollView; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.pageindicators.PageIndicator; @@ -1467,6 +1468,13 @@ public abstract class PagedView extends ViewGrou if (getNextPage() < getChildCount() -1) snapToPage(getNextPage() + 1); } + @Override + public CharSequence getAccessibilityClassName() { + // Some accessibility services have special logic for ScrollView. Since we provide same + // accessibility info as ScrollView, inform the service to handle use the same way. + return ScrollView.class.getName(); + } + /* Accessibility */ @SuppressWarnings("deprecation") @Override @@ -1479,7 +1487,6 @@ public abstract class PagedView extends ViewGrou if (getCurrentPage() > 0) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); } - info.setClassName(getClass().getName()); // Accessibility-wise, PagedView doesn't support long click, so disabling it. // Besides disabling the accessibility long-click, this also prevents this view from getting From fe48b7a57719d05baa9fa7d24261187fd83e8c42 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 3 Apr 2018 14:50:59 -0700 Subject: [PATCH 51/81] Opening all apps from all drag indicators Both the one on Home and the one on Overview open app apps. Bug: 72500733 Test: Manual Change-Id: I524937a2baed71f1dafd92add06657ae13d71ca1 --- .../views/QuickstepDragIndicator.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java index 82ec84ec62..5e9cd6e4fe 100644 --- a/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java +++ b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java @@ -50,9 +50,7 @@ public class QuickstepDragIndicator extends LauncherDragIndicator { @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); - if (isInOverview()) { - info.setContentDescription(getContext().getString(R.string.all_apps_button_label)); - } + info.setContentDescription(getContext().getString(R.string.all_apps_button_label)); } @Override @@ -64,15 +62,9 @@ public class QuickstepDragIndicator extends LauncherDragIndicator { @Override public void onClick(View view) { - if (isInOverview()) { - mLauncher.getUserEventDispatcher().logActionOnControl( - Action.Touch.TAP, ControlType.ALL_APPS_BUTTON, ContainerType.TASKSWITCHER); - mLauncher.getStateManager().goToState(ALL_APPS); - super.onClick(view); - } else { - mLauncher.getUserEventDispatcher().logActionOnControl( - Action.Touch.TAP, ControlType.ALL_APPS_BUTTON, ContainerType.WORKSPACE); - mLauncher.getStateManager().goToState(OVERVIEW); - } + mLauncher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.ALL_APPS_BUTTON, + isInOverview() ? ContainerType.TASKSWITCHER : ContainerType.WORKSPACE); + mLauncher.getStateManager().goToState(ALL_APPS); } } From ac6a6b6bf7e703bb5d40953c92c611321de9880b Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 3 Apr 2018 18:25:45 -0700 Subject: [PATCH 52/81] Removing "Page X of Y" announcement from task list Per accessibility experts request. Bug: 77549770 Test: Manual Change-Id: I351527e00e89b1c3e55a3ae4279ac962cd637a13 --- quickstep/src/com/android/quickstep/views/RecentsView.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 50a32e64bc..b8951556e9 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -950,4 +950,9 @@ public abstract class RecentsView super.notifyPageSwitchListener(prevPage); getChildAt(mCurrentPage).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); } + + @Override + protected String getCurrentPageDescription() { + return ""; + } } From b959cfb44f27aeabbe1dec8509374ce505599e8d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 4 Apr 2018 10:19:06 -0700 Subject: [PATCH 53/81] Reverting some debug logs Bug: 72481685 Change-Id: Ib9e52504d9513bd7fdede28f6c0798ca7873083d --- src/com/android/launcher3/Launcher.java | 5 ----- src/com/android/launcher3/LauncherProvider.java | 7 ------- src/com/android/launcher3/model/ModelWriter.java | 14 -------------- src/com/android/launcher3/util/TraceHelper.java | 6 ++---- 4 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ccc774a9ec..b410f4f798 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -357,11 +357,6 @@ public class Launcher extends BaseDraggingActivity if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) { mUserEventDispatcher = null; initDeviceProfile(mDeviceProfile.inv); - FileLog.d(TAG, "Config changed, my orientation=" + - getResources().getConfiguration().orientation + - ", new orientation=" + newConfig.orientation + - ", old orientation=" + mOldConfig.orientation + - ", isTransposed=" + mDeviceProfile.isVerticalBarLayout()); dispatchDeviceProfileChanged(); getRootView().dispatchInsets(); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 8b7ba20b49..7d208d48d3 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -34,7 +34,6 @@ import android.content.res.Resources; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteStatement; import android.net.Uri; @@ -56,7 +55,6 @@ import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DbDowngradeHelper; -import com.android.launcher3.model.ModelWriter; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; @@ -320,11 +318,6 @@ public class LauncherProvider extends ContentProvider { @Override public int delete(Uri uri, String selection, String[] selectionArgs) { - if (ModelWriter.DEBUG_DELETE) { - String args = selectionArgs == null ? null : TextUtils.join(",", selectionArgs); - FileLog.d(TAG, "Delete uri=" + uri + ", selection=" + selection - + ", selectionArgs=" + args, new Exception()); - } createDbIfNotExists(); SqlArguments args = new SqlArguments(uri, selection, selectionArgs); diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 72c703b2e5..eba7515248 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -50,7 +50,6 @@ import java.util.concurrent.Executor; public class ModelWriter { private static final String TAG = "ModelWriter"; - public static final boolean DEBUG_DELETE = true; private final Context mContext; private final LauncherModel mModel; @@ -257,14 +256,6 @@ public class ModelWriter { * Removes the specified items from the database */ public void deleteItemsFromDatabase(final Iterable items) { - if (DEBUG_DELETE) { - // Log it on the colling thread to get the proper stack trace - FileLog.d(TAG, "Starting item deletion", new Exception()); - for (ItemInfo item : items) { - FileLog.d(TAG, "deleting item " + item); - } - FileLog.d(TAG, "Finished deleting items"); - } ModelVerifier verifier = new ModelVerifier(); mWorkerExecutor.execute(() -> { @@ -282,11 +273,6 @@ public class ModelWriter { * Remove the specified folder and all its contents from the database. */ public void deleteFolderAndContentsFromDatabase(final FolderInfo info) { - if (DEBUG_DELETE) { - // Log it on the colling thread to get the proper stack trace - FileLog.d(TAG, "Deleting folder " + info, new Exception()); - } - ModelVerifier verifier = new ModelVerifier(); mWorkerExecutor.execute(() -> { diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java index ac381cc18c..4aa2f37885 100644 --- a/src/com/android/launcher3/util/TraceHelper.java +++ b/src/com/android/launcher3/util/TraceHelper.java @@ -24,7 +24,6 @@ import android.util.ArrayMap; import android.util.Log; import android.util.MutableLong; -import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; /** @@ -35,8 +34,7 @@ import com.android.launcher3.config.FeatureFlags; */ public class TraceHelper { - private static final boolean FORCE_LOG = Utilities.IS_DEBUG_DEVICE; - private static final boolean ENABLED = FORCE_LOG || FeatureFlags.IS_DOGFOOD_BUILD; + private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD; private static final boolean SYSTEM_TRACE = false; private static final ArrayMap sUpTimes = ENABLED ? new ArrayMap<>() : null; @@ -45,7 +43,7 @@ public class TraceHelper { if (ENABLED) { MutableLong time = sUpTimes.get(sectionName); if (time == null) { - time = new MutableLong((FORCE_LOG || isLoggable(sectionName, VERBOSE)) ? 0 : -1); + time = new MutableLong(isLoggable(sectionName, VERBOSE) ? 0 : -1); sUpTimes.put(sectionName, time); } if (time.value >= 0) { From 0c95559cbc65dee86feba07261b24f4541a05066 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 4 Apr 2018 10:23:36 -0700 Subject: [PATCH 54/81] Change overview animation to scale instead of translationX As you swipe up to overview from home, workspace scales down and fades out as before, and now recents scales down from 1.2f on top of it. The interpolators are set such that the workspace animation is seen before the recents animation. Also, we don't scale down all of recents, only the visible pages (current and adjacent). Change-Id: I5f8bfe8cafeaa41d26873c63549735d7bdff2bce --- .../launcher3/uioverrides/AllAppsState.java | 6 +- .../uioverrides/FastOverviewState.java | 4 +- .../launcher3/uioverrides/OverviewState.java | 4 +- .../PortraitStatesTouchController.java | 14 --- .../RecentsViewStateController.java | 39 +++----- .../quickstep/views/LauncherRecentsView.java | 25 ----- .../android/quickstep/views/RecentsView.java | 93 ++++++++++++++++--- .../com/android/quickstep/views/TaskView.java | 11 ++- src/com/android/launcher3/LauncherState.java | 10 +- .../WorkspaceStateTransitionAnimation.java | 9 +- .../launcher3/anim/AnimatorSetBuilder.java | 20 +++- .../android/launcher3/anim/Interpolators.java | 11 ++- 12 files changed, 143 insertions(+), 103 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java index 2626e7cccc..0e3d2a4bc2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java @@ -88,10 +88,10 @@ public class AllAppsState extends LauncherState { } @Override - public float[] getOverviewTranslationFactor(Launcher launcher) { - // Keep the same translation as in overview, so that we don't slide around when + public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) { + // Keep the same transition properties as overview, so that we don't move around when // transitioning to All Apps. - return LauncherState.OVERVIEW.getOverviewTranslationFactor(launcher); + return LauncherState.OVERVIEW.getOverviewScaleAndTranslationYFactor(launcher); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java index 99bf2649b9..f98f7a5ffa 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -50,7 +50,7 @@ public class FastOverviewState extends OverviewState { } @Override - public float[] getOverviewTranslationFactor(Launcher launcher) { - return new float[] {0f, 0.5f}; + public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) { + return new float[] {1f, 0.5f}; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index 4b2763bd91..d97b7b2643 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -58,8 +58,8 @@ public class OverviewState extends LauncherState { } @Override - public float[] getOverviewTranslationFactor(Launcher launcher) { - return new float[] {0f, 0f}; + public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) { + return new float[] {1f, 0f}; } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index 0c34b45302..1b65ca0b05 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -61,9 +61,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper(); - // If > 0, the animation progress is clamped at that value as long as user is dragging. - private float mClampProgressUpdate = -1; - // If true, we will finish the current animation instantly on second touch. private boolean mFinishFastOnSecondTouch; @@ -165,15 +162,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return builder; } - @Override - protected void updateProgress(float fraction) { - if (mClampProgressUpdate > 0) { - mCurrentAnimation.setPlayFraction(Math.min(fraction, mClampProgressUpdate)); - } else { - super.updateProgress(fraction); - } - } - @Override protected float initCurrentAnimation() { float range = getShiftRange(); @@ -189,10 +177,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr if (mFromState == NORMAL && mToState == OVERVIEW && totalShift != 0) { builder = getNormalToOverviewAnimation(); totalShift = totalShift * TOTAL_DISTANCE_MULTIPLIER; - mClampProgressUpdate = MAXIMUM_DISTANCE_FACTOR; } else { builder = new AnimatorSetBuilder(); - mClampProgressUpdate = -1; } if (mPendingAnimation != null) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 9f7fef33d2..124ec202d1 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -15,11 +15,11 @@ */ package com.android.launcher3.uioverrides; -import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATION; +import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_X_FACTOR; import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR; +import static com.android.quickstep.views.RecentsView.ADJACENT_SCALE; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import android.animation.ValueAnimator; @@ -30,7 +30,6 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.StateHandler; -import com.android.launcher3.PagedView; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.PropertySetter; import com.android.quickstep.views.LauncherRecentsView; @@ -49,9 +48,9 @@ public class RecentsViewStateController implements StateHandler { @Override public void setState(LauncherState state) { mRecentsView.setContentAlpha(state.overviewUi ? 1 : 0); - float[] translationFactor = state.getOverviewTranslationFactor(mLauncher); - mRecentsView.setTranslationXFactor(translationFactor[0]); - mRecentsView.setTranslationYFactor(translationFactor[1]); + float[] scaleTranslationYFactor = state.getOverviewScaleAndTranslationYFactor(mLauncher); + mRecentsView.setAdjacentScale(scaleTranslationYFactor[0]); + mRecentsView.setTranslationYFactor(scaleTranslationYFactor[1]); if (state.overviewUi) { mRecentsView.updateEmptyMessage(); mRecentsView.resetTaskVisuals(); @@ -61,28 +60,18 @@ public class RecentsViewStateController implements StateHandler { @Override public void setStateWithAnimation(final LauncherState toState, AnimatorSetBuilder builder, AnimationConfig config) { - - // Scroll to the workspace card before changing to the NORMAL state. - LauncherState fromState = mLauncher.getStateManager().getState(); - int currPage = mRecentsView.getCurrentPage(); - if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) { - int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION; - int durationPerPage = maxSnapDuration / 10; - int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage); - mRecentsView.snapToPage(0, snapDuration); - // Let the snapping animation play for a bit before we translate off screen. - builder.setStartDelay(snapDuration / 4); - } - PropertySetter setter = config.getProperSetter(builder); - float[] translationFactor = toState.getOverviewTranslationFactor(mLauncher); - setter.setFloat(mRecentsView, TRANSLATION_X_FACTOR, - translationFactor[0], + float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher); + setter.setFloat(mRecentsView, ADJACENT_SCALE, scaleTranslationYFactor[0], builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR)); - setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, - translationFactor[1], + setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1], builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR)); - setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, LINEAR); + setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, + AGGRESSIVE_EASE_IN_OUT); + + if (!toState.overviewUi) { + builder.addOnFinishRunnable(mRecentsView::resetTaskVisuals); + } if (toState.overviewUi) { ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index d428f23dac..6788827445 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -20,7 +20,6 @@ import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; -import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.TargetApi; @@ -45,20 +44,6 @@ import com.android.launcher3.R; @TargetApi(Build.VERSION_CODES.O) public class LauncherRecentsView extends RecentsView implements Insettable { - public static final FloatProperty TRANSLATION_X_FACTOR = - new FloatProperty("translationXFactor") { - - @Override - public void setValue(LauncherRecentsView view, float v) { - view.setTranslationXFactor(v); - } - - @Override - public Float get(LauncherRecentsView view) { - return view.mTranslationXFactor; - } - }; - public static final FloatProperty TRANSLATION_Y_FACTOR = new FloatProperty("translationYFactor") { @@ -73,8 +58,6 @@ public class LauncherRecentsView extends RecentsView implements Insett } }; - @ViewDebug.ExportedProperty(category = "launcher") - private float mTranslationXFactor; @ViewDebug.ExportedProperty(category = "launcher") private float mTranslationYFactor; @@ -114,11 +97,6 @@ public class LauncherRecentsView extends RecentsView implements Insett setTranslationYFactor(mTranslationYFactor); } - public void setTranslationXFactor(float translationFactor) { - mTranslationXFactor = translationFactor; - invalidate(); - } - public void setTranslationYFactor(float translationFactor) { mTranslationYFactor = translationFactor; setTranslationY(mTranslationYFactor * (mPagePadding.bottom - mPagePadding.top)); @@ -127,10 +105,7 @@ public class LauncherRecentsView extends RecentsView implements Insett @Override public void draw(Canvas canvas) { maybeDrawEmptyMessage(canvas); - int count = canvas.save(); - canvas.translate(mTranslationXFactor * (mIsRtl ? -getWidth() : getWidth()), 0); super.draw(canvas); - canvas.restoreToCount(count); } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e7f69b7b38..f6b6abdac3 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -59,8 +59,8 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.util.Themes; import com.android.launcher3.util.PendingAnimation; +import com.android.launcher3.util.Themes; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; @@ -85,8 +85,6 @@ public abstract class RecentsView public static final FloatProperty CONTENT_ALPHA = new FloatProperty("contentAlpha") { - - @Override public void setValue(RecentsView recentsView, float v) { recentsView.setContentAlpha(v); @@ -98,6 +96,20 @@ public abstract class RecentsView } }; + + + public static final FloatProperty ADJACENT_SCALE = + new FloatProperty("adjacentScale") { + @Override + public void setValue(RecentsView recentsView, float v) { + recentsView.setAdjacentScale(v); + } + + @Override + public Float get(RecentsView recentsView) { + return recentsView.mAdjacentScale; + } + }; private static final String PREF_FLIP_RECENTS = "pref_flip_recents"; private static final int DISMISS_TASK_DURATION = 300; @@ -145,6 +157,8 @@ public abstract class RecentsView @ViewDebug.ExportedProperty(category = "launcher") private float mContentAlpha = 1; + @ViewDebug.ExportedProperty(category = "launcher") + private float mAdjacentScale = 1; // Keeps track of task views whose visual state should not be reset private ArraySet mIgnoreResetTaskViews = new ArraySet<>(); @@ -803,10 +817,58 @@ public abstract class RecentsView setVisibility(alpha > 0 ? VISIBLE : GONE); } + public void setAdjacentScale(float adjacentScale) { + if (mAdjacentScale == adjacentScale) { + return; + } + mAdjacentScale = adjacentScale; + TaskView currTask = getPageAt(mCurrentPage); + if (currTask == null) { + return; + } + currTask.setScaleX(mAdjacentScale); + currTask.setScaleY(mAdjacentScale); + + if (mCurrentPage - 1 >= 0) { + TaskView adjacentTask = getPageAt(mCurrentPage - 1); + float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask, + mAdjacentScale, 0); + adjacentTask.setScaleX(scaleAndTranslation[0]); + adjacentTask.setScaleY(scaleAndTranslation[0]); + adjacentTask.setTranslationX(-scaleAndTranslation[1]); + adjacentTask.setTranslationY(scaleAndTranslation[2]); + } + if (mCurrentPage + 1 < getChildCount()) { + TaskView adjacentTask = getPageAt(mCurrentPage + 1); + float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask, + mAdjacentScale, 0); + adjacentTask.setScaleX(scaleAndTranslation[0]); + adjacentTask.setScaleY(scaleAndTranslation[0]); + adjacentTask.setTranslationX(scaleAndTranslation[1]); + adjacentTask.setTranslationY(scaleAndTranslation[2]); + } + } + + private float[] getAdjacentScaleAndTranslation(TaskView currTask, TaskView adjacentTask, + float currTaskToScale, float currTaskToTranslationY) { + float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale()); + return new float[] { + currTaskToScale * adjacentTask.getCurveScale(), + mIsRtl ? -displacement : displacement, + currTaskToTranslationY + }; + } + @Override public void onViewAdded(View child) { super.onViewAdded(child); child.setAlpha(mContentAlpha); + setAdjacentScale(mAdjacentScale); + } + + @Override + public TaskView getPageAt(int index) { + return (TaskView) getChildAt(index); } public void updateEmptyMessage() { @@ -884,18 +946,24 @@ public abstract class RecentsView float toScale = endInterpolation.taskScale; float toTranslationY = endInterpolation.taskY; - float displacementX = tv.getWidth() * (toScale - tv.getScaleX()); if (launchingCenterTask) { + TaskView centerTask = getPageAt(centerTaskIndex); if (taskIndex - 1 >= 0) { - anim.play(createAnimForChild( - taskIndex - 1, toScale, displacementX, toTranslationY)); + TaskView adjacentTask = getPageAt(taskIndex - 1); + float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask, + adjacentTask, toScale, toTranslationY); + scaleAndTranslation[1] = -scaleAndTranslation[1]; + anim.play(createAnimForChild(adjacentTask, scaleAndTranslation)); } if (taskIndex + 1 < getPageCount()) { - anim.play(createAnimForChild( - taskIndex + 1, toScale, -displacementX, toTranslationY)); + TaskView adjacentTask = getPageAt(taskIndex + 1); + float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask, + adjacentTask, toScale, toTranslationY); + anim.play(createAnimForChild(adjacentTask, scaleAndTranslation)); } } else { // We are launching an adjacent task, so parallax the center and other adjacent task. + float displacementX = tv.getWidth() * (toScale - tv.getCurveScale()); anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), TRANSLATION_X, mIsRtl ? -displacementX : displacementX)); @@ -911,13 +979,12 @@ public abstract class RecentsView return anim; } - private ObjectAnimator createAnimForChild(int childIndex, float toScale, float tx, float ty) { - View child = getChildAt(childIndex); + private ObjectAnimator createAnimForChild(View child, float[] toScaleAndTranslation) { return ObjectAnimator.ofPropertyValuesHolder(child, new PropertyListBuilder() - .scale(child.getScaleX() * toScale) - .translationY(ty) - .translationX(mIsRtl ? tx : -tx) + .scale(child.getScaleX() * toScaleAndTranslation[0]) + .translationX(toScaleAndTranslation[1]) + .translationY(toScaleAndTranslation[2]) .build()); } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 57516b09fa..42da472b5c 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -70,6 +70,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback private Task mTask; private TaskThumbnailView mSnapshotView; private ImageView mIconView; + private float mCurveScale; public TaskView(Context context) { this(context, null); @@ -178,9 +179,13 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA); - float scale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; - setScaleX(scale); - setScaleY(scale); + mCurveScale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; + setScaleX(mCurveScale); + setScaleY(mCurveScale); + } + + public float getCurveScale() { + return mCurveScale; } @Override diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index fdb6f482ad..4697b82f81 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -181,12 +181,12 @@ public class LauncherState { } /** - * Returns 2 floats designating how much to translate overview: - * X factor is based on width, e.g. 0 is fully onscreen and 1 is fully offscreen - * Y factor is based on padding, e.g. 0 is top aligned and 0.5 is centered vertically + * Returns 2 floats designating how to transition overview: + * scale for the current and adjacent pages + * translationY factor where 0 is top aligned and 0.5 is centered vertically */ - public float[] getOverviewTranslationFactor(Launcher launcher) { - return new float[] {1f, 0f}; + public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) { + return new float[] {1.2f, 0.2f}; } public void onStateEnabled(Launcher launcher) { diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index fa86906cf6..420a7c4182 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -31,7 +31,6 @@ import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.graphics.ViewScrim; -import com.android.launcher3.uioverrides.UiFactory; /** * Manages the animations between each of the workspace states. @@ -74,11 +73,11 @@ public class WorkspaceStateTransitionAnimation { propertySetter); } - propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_IN); + propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_OUT); propertySetter.setFloat(mWorkspace, View.TRANSLATION_X, - scaleAndTranslation[1], Interpolators.ZOOM_IN); + scaleAndTranslation[1], Interpolators.ZOOM_OUT); propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y, - scaleAndTranslation[2], Interpolators.ZOOM_IN); + scaleAndTranslation[2], Interpolators.ZOOM_OUT); int elements = state.getVisibleElements(mLauncher); float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; @@ -113,7 +112,7 @@ public class WorkspaceStateTransitionAnimation { int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0)); propertySetter.setInt(cl.getScrimBackground(), - DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN); + DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_OUT); propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA, pageAlpha, pageAlphaProvider.interpolator); } diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java index 919104886a..b209a2deeb 100644 --- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java +++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java @@ -16,6 +16,7 @@ package com.android.launcher3.anim; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.util.SparseArray; import android.view.animation.Interpolator; @@ -23,6 +24,7 @@ import android.view.animation.Interpolator; import com.android.launcher3.LauncherAnimUtils; import java.util.ArrayList; +import java.util.List; /** * Utility class for building animator set @@ -35,7 +37,7 @@ public class AnimatorSetBuilder { protected final ArrayList mAnims = new ArrayList<>(); private final SparseArray mInterpolators = new SparseArray<>(); - private long mStartDelay = 0; + private List mOnFinishRunnables = new ArrayList<>(); /** * Associates a tag with all the animations added after this call. @@ -46,14 +48,24 @@ public class AnimatorSetBuilder { mAnims.add(anim); } - public void setStartDelay(long startDelay) { - mStartDelay = startDelay; + public void addOnFinishRunnable(Runnable onFinishRunnable) { + mOnFinishRunnables.add(onFinishRunnable); } public AnimatorSet build() { AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); anim.playTogether(mAnims); - anim.setStartDelay(mStartDelay); + if (!mOnFinishRunnables.isEmpty()) { + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + for (Runnable onFinishRunnable : mOnFinishRunnables) { + onFinishRunnable.run(); + } + mOnFinishRunnables.clear(); + } + }); + } return anim; } diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java index 6078776e0d..06ddf22086 100644 --- a/src/com/android/launcher3/anim/Interpolators.java +++ b/src/com/android/launcher3/anim/Interpolators.java @@ -65,15 +65,22 @@ public class Interpolators { new PathInterpolator(0.3f, 0f, 0.1f, 1f); /** - * Inversion of zInterpolate, compounded with an ease-out. + * Inversion of ZOOM_OUT, compounded with an ease-out. */ public static final Interpolator ZOOM_IN = new Interpolator() { + @Override + public float getInterpolation(float v) { + return DEACCEL_3.getInterpolation(1 - ZOOM_OUT.getInterpolation(1 - v)); + } + }; + + public static final Interpolator ZOOM_OUT = new Interpolator() { private static final float FOCAL_LENGTH = 0.35f; @Override public float getInterpolation(float v) { - return DEACCEL_3.getInterpolation(1 - zInterpolate(1 - v)); + return zInterpolate(v); } /** From bc5bfc11196d40234f077b1e8de07e4d9ad80263 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 29 Mar 2018 18:00:04 -0700 Subject: [PATCH 55/81] Make recents animation work with fallback activity. Bug: 77157702 Bug: 77152886 Change-Id: Ide312b750efb8214a7c262f7380b5dbd2ef4647f --- .../LauncherAppTransitionManagerImpl.java | 39 +++++++++-- .../quickstep/ActivityControlHelper.java | 67 ++++++++++++++---- .../quickstep/OtherActivityTouchConsumer.java | 2 +- .../quickstep/OverviewCommandHelper.java | 69 +++++++++---------- ...a => RecentsAnimationActivityOptions.java} | 31 ++++++--- .../com/android/quickstep/RecentsModel.java | 10 +++ .../WindowTransformSwipeHandler.java | 14 +++- .../android/quickstep/views/RecentsView.java | 37 ++++++++++ 8 files changed, 201 insertions(+), 68 deletions(-) rename quickstep/src/com/android/quickstep/{FallbackActivityOptions.java => RecentsAnimationActivityOptions.java} (71%) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index e4a8f36497..307345a30a 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -106,6 +106,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private DeviceProfile mDeviceProfile; private View mFloatingView; + private RemoteAnimationRunnerCompat mRemoteAnimationOverride; + private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -175,6 +177,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } + public void setRemoteAnimationOverride(RemoteAnimationRunnerCompat remoteAnimationOverride) { + mRemoteAnimationOverride = remoteAnimationOverride; + } + /** * Try to find a TaskView that corresponds with the component of the launched view. * @@ -635,6 +641,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * Registers remote animations used when closing apps to home screen. */ private void registerRemoteAnimations() { + // Unregister this if (hasControlRemoteAppTransitionPermission()) { try { RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat(); @@ -669,12 +676,36 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private RemoteAnimationRunnerCompat getWallpaperOpenRunner() { return new LauncherAnimationRunner(mHandler) { @Override - public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - if (mLauncher.getStateManager().getState().overviewUi) { - // We use a separate transition for Overview mode. - return null; + public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, + Runnable runnable) { + if (mLauncher.getStateManager().getState().overviewUi + && mRemoteAnimationOverride != null) { + // This transition is only used for the fallback activity and should not be + // managed here (but necessary to implement here since the defined remote + // animation currently takes precendence over the one defined in the activity + // options). + mRemoteAnimationOverride.onAnimationStart(targetCompats, runnable); + return; } + super.onAnimationStart(targetCompats, runnable); + } + @Override + public void onAnimationCancelled() { + if (mLauncher.getStateManager().getState().overviewUi + && mRemoteAnimationOverride != null) { + // This transition is only used for the fallback activity and should not be + // managed here (but necessary to implement here since the defined remote + // animation currently takes precendence over the one defined in the activity + // options). + mRemoteAnimationOverride.onAnimationCancelled(); + return; + } + super.onAnimationCancelled(); + } + + @Override + public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { AnimatorSet anim = new AnimatorSet(); anim.play(getClosingWindowAnimators(targetCompats)); diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 4e3528c84d..3e96c4452e 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -36,8 +36,10 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; +import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.ViewOnDrawExecutor; @@ -80,7 +82,10 @@ public interface ActivityControlHelper { ActivityInitListener createActivityInitListener(BiPredicate onInitListener); - void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver, + void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver, + final RecentsAnimationListener remoteAnimationListener); + + void startRecentsFromButton(Context context, Intent intent, RecentsAnimationListener remoteAnimationListener); @UiThread @@ -203,21 +208,44 @@ public interface ActivityControlHelper { } @Override - public void startRecents(Context context, Intent intent, - AssistDataReceiver assistDataReceiver, - RecentsAnimationListener remoteAnimationListener) { + public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver, + final RecentsAnimationListener remoteAnimationListener) { ActivityManagerWrapper.getInstance().startRecentsActivity( intent, assistDataReceiver, remoteAnimationListener, null, null); } + @Override + public void startRecentsFromButton(Context context, Intent intent, + RecentsAnimationListener remoteAnimationListener) { + // We should use the remove animation for the fallback activity recents button case, + // it works better with PiP. In Launcher, we have already registered the remote + // animation definition, which takes priority over explicitly defined remote + // animations in the provided activity options when starting the activity, so we + // just register a remote animation factory to get a callback to handle this. + LauncherAppTransitionManagerImpl appTransitionManager = + (LauncherAppTransitionManagerImpl) getLauncher().getAppTransitionManager(); + appTransitionManager.setRemoteAnimationOverride(new RecentsAnimationActivityOptions( + remoteAnimationListener, () -> { + // Once the controller is finished, also reset the remote animation override + appTransitionManager.setRemoteAnimationOverride(null); + })); + context.startActivity(intent); + } + + @Nullable + @UiThread + private Launcher getLauncher() { + LauncherAppState app = LauncherAppState.getInstanceNoCreate(); + if (app == null) { + return null; + } + return (Launcher) app.getModel().getCallback(); + } + @Nullable @UiThread private Launcher getVisibleLaucher() { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app == null) { - return null; - } - Launcher launcher = (Launcher) app.getModel().getCallback(); + Launcher launcher = getLauncher(); return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ? launcher : null; } @@ -325,12 +353,23 @@ public interface ActivityControlHelper { } @Override - public void startRecents(Context context, Intent intent, - AssistDataReceiver assistDataReceiver, + public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver, final RecentsAnimationListener remoteAnimationListener) { - ActivityOptions options = - ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat( - new FallbackActivityOptions(remoteAnimationListener), 10000, 10000)); + // We can use the normal recents animation for swipe up + ActivityManagerWrapper.getInstance().startRecentsActivity( + intent, assistDataReceiver, remoteAnimationListener, null, null); + } + + @Override + public void startRecentsFromButton(Context context, Intent intent, + RecentsAnimationListener remoteAnimationListener) { + // We should use the remove animation for the fallback activity recents button case, + // it works better with PiP. For the fallback activity, we should not have registered + // the launcher app transition manager, so we should just start the remote animation here. + ActivityOptions options = ActivityOptionsCompat.makeRemoteAnimation( + new RemoteAnimationAdapterCompat( + new RecentsAnimationActivityOptions(remoteAnimationListener, null), + 10000, 10000)); context.startActivity(intent, options.toBundle()); } diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 0ab2df7e4c..4d695de907 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -218,7 +218,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC handler.initWhenReady(); TraceHelper.beginSection("RecentsController"); - Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent, + Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent, new AssistDataReceiver() { @Override public void onHandleAssistData(Bundle bundle) { diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 985a36490e..8e59578a23 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -53,6 +53,7 @@ import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHel import com.android.quickstep.util.SysuiEventLogger; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; import com.android.systemui.shared.recents.view.RecentsTransition; @@ -77,7 +78,7 @@ public class OverviewCommandHelper extends InternalStateHandler { private static final int RID_CANCEL_CONTROLLER = 1; private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2; - private static final long RECENTS_LAUNCH_DURATION = 150; + private static final long RECENTS_LAUNCH_DURATION = 200; private static final String TAG = "OverviewCommandHelper"; private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false; @@ -151,12 +152,13 @@ public class OverviewCommandHelper extends InternalStateHandler { private void initSwipeHandler(ActivityControlHelper helper, long time, Consumer onAnimationInitCallback) { final int commandId = mCurrentCommandId; - RunningTaskInfo taskInfo = ActivityManagerWrapper.getInstance().getRunningTask(); + final RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); + final int runningTaskId = runningTask.id; final WindowTransformSwipeHandler handler = - new WindowTransformSwipeHandler(taskInfo, mContext, time, helper); + new WindowTransformSwipeHandler(runningTask, mContext, time, helper); // Preload the plan - mRecentsModel.loadTasks(taskInfo.id, null); + mRecentsModel.loadTasks(runningTaskId, null); mWindowTransformSwipeHandler = handler; mTempTaskTargetRect.setEmpty(); @@ -172,13 +174,8 @@ public class OverviewCommandHelper extends InternalStateHandler { addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset); TraceHelper.beginSection(TAG); - Runnable startActivity = () -> helper.startRecents(mContext, homeIntent, - new AssistDataReceiver() { - @Override - public void onHandleAssistData(Bundle bundle) { - mRecentsModel.preloadAssistData(taskInfo.id, bundle); - } - }, + Runnable startActivity = () -> helper.startRecentsFromButton(mContext, + addToIntent(homeIntent), new RecentsAnimationListener() { public void onAnimationStart( RecentsAnimationControllerCompat controller, @@ -190,11 +187,17 @@ public class OverviewCommandHelper extends InternalStateHandler { minimizedHomeBounds); mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize)); + ThumbnailData thumbnail = mAM.getTaskThumbnail(runningTaskId, + true /* reducedResolution */); mMainThreadExecutor.execute(() -> { addFinishCommand(commandId, RID_CANCEL_CONTROLLER, () -> controller.finish(true)); if (commandId == mCurrentCommandId) { onAnimationInitCallback.accept(handler); + + // The animation has started, which means the other activity + // should be paused, lets update the thumbnail + handler.switchToScreenshotImmediate(thumbnail); } }); } else { @@ -230,7 +233,7 @@ public class OverviewCommandHelper extends InternalStateHandler { }); handler.onGestureStarted(); anim.setDuration(RECENTS_LAUNCH_DURATION); - anim.setInterpolator(Interpolators.AGGRESSIVE_EASE); + anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); anim.start(); addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel); } @@ -241,6 +244,7 @@ public class OverviewCommandHelper extends InternalStateHandler { return; } + ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps"); long time = SystemClock.elapsedRealtime(); mMainThreadExecutor.execute(() -> { long elapsedTime = time - mLastToggleTime; @@ -248,40 +252,37 @@ public class OverviewCommandHelper extends InternalStateHandler { mCurrentCommandId++; mTempTaskTargetRect.round(mTaskTargetRect); - boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout(); int runnableCount = mCurrentCommandFinishRunnables.size(); if (runnableCount > 0) { for (int i = 0; i < runnableCount; i++) { mCurrentCommandFinishRunnables.valueAt(i).run(); } mCurrentCommandFinishRunnables.clear(); - isQuickTap = true; } + // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows + // the menu activity which takes window focus, prevening the right condition from + // being run below ActivityControlHelper helper = getActivityControlHelper(); RecentsView recents = helper.getVisibleRecentsView(); if (recents != null) { - int childCount = recents.getChildCount(); - if (childCount != 0) { - ((TaskView) recents.getChildAt(childCount >= 2 ? 1 : 0)).launchTask(true); + // Launch the next task + recents.showNextTask(); + } else { + if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { + // The user tried to launch back into overview too quickly, either after + // launching an app, or before overview has actually shown, just ignore for now + return; } - // There are not enough tasks. Skip - return; + // Start overview + if (helper.switchToRecentsIfVisible()) { + SysuiEventLogger.writeDummyRecentsTransition(0); + // Do nothing + } else { + initSwipeHandler(helper, time, this::startZoomOutAnim); + } } - - if (isQuickTap) { - // Focus last task. Start is on background thread so that all ActivityManager calls - // are serialized - BackgroundExecutor.get().submit(this::startLastTask); - return; - } - if (helper.switchToRecentsIfVisible()) { - SysuiEventLogger.writeDummyRecentsTransition(0); - return; - } - - initSwipeHandler(helper, time, this::startZoomOutAnim); }); } @@ -362,10 +363,6 @@ public class OverviewCommandHelper extends InternalStateHandler { return false; } - public boolean isUsingFallbackActivity() { - return DEBUG_START_FALLBACK_ACTIVITY; - } - public ActivityControlHelper getActivityControlHelper() { if (DEBUG_START_FALLBACK_ACTIVITY) { return new FallbackActivityControllerHelper(); diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java similarity index 71% rename from quickstep/src/com/android/quickstep/FallbackActivityOptions.java rename to quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java index 04352c390b..a25e192dc2 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java @@ -24,24 +24,33 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; +import java.util.function.Consumer; /** - * Temporary class to create activity options to emulate recents transition for fallback activtiy. + * Class to create activity options to emulate recents transition. */ -public class FallbackActivityOptions implements RemoteAnimationRunnerCompat { +public class RecentsAnimationActivityOptions implements RemoteAnimationRunnerCompat { private final RecentsAnimationListener mListener; + private final Runnable mFinishCallback; - public FallbackActivityOptions(RecentsAnimationListener listener) { + public RecentsAnimationActivityOptions(RecentsAnimationListener listener, + Runnable finishCallback) { mListener = listener; + mFinishCallback = finishCallback; } @Override public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) { showOpeningTarget(targetCompats); - DummyRecentsAnimationControllerCompat dummyRecentsAnim = - new DummyRecentsAnimationControllerCompat(runnable); + RemoteRecentsAnimationControllerCompat dummyRecentsAnim = + new RemoteRecentsAnimationControllerCompat(() -> { + runnable.run(); + if (mFinishCallback != null) { + mFinishCallback.run(); + } + }); Rect insets = new Rect(); WindowManagerWrapper.getInstance().getStableInsets(insets); @@ -54,23 +63,22 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat { } private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) { + TransactionCompat t = new TransactionCompat(); for (RemoteAnimationTargetCompat target : targetCompats) { - TransactionCompat t = new TransactionCompat(); int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING ? Integer.MAX_VALUE : target.prefixOrderIndex; t.setLayer(target.leash, layer); t.show(target.leash); - t.apply(); } + t.apply(); } - private static class DummyRecentsAnimationControllerCompat - extends RecentsAnimationControllerCompat { + private class RemoteRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat { final Runnable mFinishCallback; - public DummyRecentsAnimationControllerCompat(Runnable finishCallback) { + public RemoteRecentsAnimationControllerCompat(Runnable finishCallback) { mFinishCallback = finishCallback; } @@ -87,7 +95,8 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat { @Override public void finish(boolean toHome) { - if (toHome) { + // This should never be called with toHome == false + if (mFinishCallback != null) { mFinishCallback.run(); } } diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 1e43202a1f..4652f2d656 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -158,6 +158,16 @@ public class RecentsModel extends TaskStackChangeListener { return requestId; } + @Override + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { + mTaskChangeId++; + } + + @Override + public void onActivityUnpinned() { + mTaskChangeId++; + } + @Override public void onTaskStackChanged() { mTaskChangeId++; diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 36a9d56496..975c62ba49 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -196,6 +196,10 @@ public class WindowTransformSwipeHandler { private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; + // Only used with the recents activity, when the screenshot should be fetched at the beginning + // of the animation and not at the end when the activity is already paused + private boolean mSkipScreenshotAtEndOfTransition; + WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, ActivityControlHelper controller) { mContext = context; @@ -582,7 +586,6 @@ public class WindowTransformSwipeHandler { mSourceStackBounds.set(target.sourceContainerBounds); initTransitionEndpoints(dp); - break; } } } @@ -725,8 +728,9 @@ public class WindowTransformSwipeHandler { () -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE)); } }; + synchronized (mRecentsAnimationWrapper) { - if (mRecentsAnimationWrapper.controller != null) { + if (mRecentsAnimationWrapper.controller != null && !mSkipScreenshotAtEndOfTransition) { TransactionCompat transaction = new TransactionCompat(); for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { if (app.mode == MODE_CLOSING) { @@ -753,6 +757,12 @@ public class WindowTransformSwipeHandler { doLogGesture(true /* toLauncher */); } + @UiThread + public void switchToScreenshotImmediate(ThumbnailData thumbnail) { + mRecentsView.updateThumbnail(mRunningTaskId, thumbnail); + mSkipScreenshotAtEndOfTransition = true; + } + private void setupLauncherUiAfterSwipeUpAnimation() { if (mLauncherTransitionController != null) { mLauncherTransitionController.getAnimationPlayer().end(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e7f69b7b38..592dc2deb6 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -126,6 +126,26 @@ public abstract class RecentsView } } } + + @Override + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { + // Check this is for the right user + if (!checkCurrentUserId(userId, false /* debug */)) { + return; + } + + // Remove the task immediately from the task list + TaskView taskView = getTaskView(taskId); + if (taskView != null) { + removeView(taskView); + } + } + + @Override + public void onActivityUnpinned() { + // TODO: Re-enable layout transitions for addition of the unpinned task + reloadIfNeeded(); + } }; private int mLoadPlanId = -1; @@ -581,6 +601,23 @@ public abstract class RecentsView } } + public void showNextTask() { + TaskView runningTaskView = getTaskView(mRunningTaskId); + if (runningTaskView == null) { + // Launch the first task + if (getChildCount() > 0) { + ((TaskView) getChildAt(0)).launchTask(true /* animate */); + } + } else { + // Get the next launch task + int runningTaskIndex = indexOfChild(runningTaskView); + int nextTaskIndex = Math.max(0, Math.min(getChildCount() - 1, runningTaskIndex + 1)); + if (nextTaskIndex < getChildCount()) { + ((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */); + } + } + } + public QuickScrubController getQuickScrubController() { return mQuickScrubController; } From 9800e730a2ab7469002cf971ad9c8dd92d3cf372 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 4 Apr 2018 13:33:23 -0700 Subject: [PATCH 56/81] Fix animations home - To prevent surface thrashing, we no longer hide the home activity before starting the transition home. This prevents the launcher from being added to the remote animation target list, which means that we default to skipping the launcher animation. As a workaround, we special case the flow and force the animation to run when starting the recents animation. Bug: 74405472 Test: Go home from an app, ensure there is an animation. Change-Id: Ifd2b39444fdeab323ee79a368b580a6264c3e5b9 --- .../LauncherAppTransitionManagerImpl.java | 11 +++++++++- .../WindowTransformSwipeHandler.java | 6 ++++++ src/com/android/launcher3/BaseActivity.java | 20 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 307345a30a..dffe641d86 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -709,11 +709,20 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag AnimatorSet anim = new AnimatorSet(); anim.play(getClosingWindowAnimators(targetCompats)); - if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) { + // Normally, we run the launcher content animation when we are transitioning home, + // but if home is already visible, then we don't want to animate the contents of + // launcher unless we know that we are animating home as a result of the home button + // press with quickstep, which will result in launcher being started on touch down, + // prior to the animation home (and won't be in the targets list because it is + // already visible). In that case, we force invisibility on touch down, and only + // reset it after the animation to home is initialized. + if (launcherIsATargetWithMode(targetCompats, MODE_OPENING) + || mLauncher.isForceInvisible()) { // Only register the content animation for cancellation when state changes mLauncher.getStateManager().setCurrentAnimation(anim); createLauncherResumeAnimation(anim); } + mLauncher.setForceInvisible(false); return anim; } }; diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 975c62ba49..f6cf85a52d 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -340,6 +340,9 @@ public class WindowTransformSwipeHandler { } mWasLauncherAlreadyVisible = alreadyOnHome; mActivity = activity; + // Override the visibility of the activity until the gesture actually starts and we swipe + // up, or until we transition home and the home animation is composed + mActivity.setForceInvisible(true); mRecentsView = activity.getOverviewPanel(); mQuickScrubController = mRecentsView.getQuickScrubController(); @@ -613,6 +616,9 @@ public class WindowTransformSwipeHandler { private void notifyGestureStarted() { final T curActivity = mActivity; if (curActivity != null) { + // Once the gesture starts, we can no longer transition home through the button, so + // reset the force override of the activity visibility + mActivity.setForceInvisible(false); mActivityControlHelper.onQuickstepGestureStarted( curActivity, mWasLauncherAlreadyVisible); } diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index cf2d79faf2..ae631a4466 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -39,6 +39,9 @@ public abstract class BaseActivity extends Activity { protected SystemUiController mSystemUiController; private boolean mStarted; + // When the recents animation is running, the visibility of the Launcher is managed by the + // animation + private boolean mForceInvisible; private boolean mUserActive; public DeviceProfile getDeviceProfile() { @@ -100,6 +103,7 @@ public abstract class BaseActivity extends Activity { @Override protected void onStop() { mStarted = false; + mForceInvisible = false; super.onStop(); } @@ -125,6 +129,22 @@ public abstract class BaseActivity extends Activity { } } + /** + * Used to set the override visibility state, used only to handle the transition home with the + * recents animation. + * @see LauncherAppTransitionManagerImpl.getWallpaperOpenRunner() + */ + public void setForceInvisible(boolean invisible) { + mForceInvisible = invisible; + } + + /** + * @return Wether this activity should be considered invisible regardless of actual visibility. + */ + public boolean isForceInvisible() { + return mForceInvisible; + } + /** * Sets the device profile, adjusting it accordingly in case of multi-window */ From 6dcf030c498a5ea4aab39233fb25b500be6e8055 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 4 Apr 2018 14:41:51 -0700 Subject: [PATCH 57/81] Updating the system shared lib Change-Id: I442e124bb8b78f89c23605ce311400032d7ccdad --- quickstep/libs/sysui_shared.jar | Bin 120112 -> 119538 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index 3c5033e554a7484f00b66fccb69a495605b1d607..b75a1930654cac043efecffa1ed137e52b6f9de2 100644 GIT binary patch delta 13812 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 nl%Lr?_GhS6L3N6Yl>3NiR|h delta 14209 zcmZvD1z1$y^Ea37?v#}766r1h>F(~9UO*ZNsilz)=~`ME0cjB>Bo%3-6hU~G#c%!I zzYmW)%zP%!oHOSR+~K4YrM?OUOG5<#kq{0Q6%|gy>iJ775rn%B<>0%IhB12J?z8C_ zP(pzbqG)L_BK3?`5G+{(U^NlrRl_i;$ABRCpccRaC)EN-O;`jv_drp!f7lpJP2}SD zhR$dg?@iCp>)q=&90)X-Ge)A_`2qK$0RpM!jL1#&T+7HX&Se0=kvg4%4eqT6sGE!g zO=0Y&F40_cSY$>Dwn#AGgZz77)2-?T%vdV+Fw~YkQ7X3)BDkOtz;2S%+q-wpY0&al z@GwXdx6x0`J1fxDK%=owfrpv=PVvVix05FkjB|qk2!N-Xp^^Ly#kn`(GA#g>Yyn7{ z^uo^&??6pz(V7@A^j%0z(<#6|K&UD@IHVOC3vJpm3=O_>0_JW5h`@WT0B)0JmKy@h z%3!YJeXuMzFJi1JW->>^G89I2d6CiAoo6CUlQ+e_Qz)%%*Fm^Y9 z1{UiAP@6bE#Qq<$CiqWH_w2g}{!+ndLSC-GgSl!r*t%ap=4t0Wkkdc_?A8q+r<(qL z(A048=>Om|pLaw#oGOJ?CyUs*p$k@P(;Cpx#}GvJn(6D(lF2*z%97yzWNr0cvJ>Ja z3e5HnSM(@N8P@N-4sLNj1y)}uYPo((R-h2gI9%5Hx?Dqcty3y%oK#T~o|qJ^-rcAu z$Lw?-UIe1&dHXUz*X1mB5mBAMPMwc)xS!$al+zjR!>HIdVS5(r5xg8OWMwEHIg|?- zW#Up>Cm@~fO;gWK6!kof7nCUDh<3(!eSUr+{`?*Li+(_Dzam9t>xT%JowDdhG^cHw z#W8&1YQ<{7F>E*q~u4altzAy#f}Pd5}mrAx!`oj}EBD_(OclD5OxHOwkG zcyU!$@%Yh7IlYn3$&JPi@4M@Agf`_P_N31iSugQ~kl||h2}(w1r$!98bBj%=vb43T zCJw^qL0_M}tPGaE=*EzXwa%vu6MK55KY48tl9y3gK27yQS=^63=t|=1t1>2f73=2apjMAh+l@9I^<36MW$yzVG$LlRc4aq z?e8r?T~+Y~{SBa@f`TgBTY+E!4+nRN1P2GbiP8VLitjE26)+JIpa@EoUB`frK$L*z z2@Fx9c=W|kA>-K(U%PyNTj==;x&G041mq4pr1!&ft6a}bB%E~eGg6@3_A&026EL3L zaegWzHG;~y*A`y-wCnk^`TFYhswgK+0*=pb-4zx^lWUvC@(gACF!jbVoN~^#+8b?u zJ-e3t_{8Ct&tdFglK~zm!yO*f{@Ns?`2e-9HyLwxb}H9`Sr#yCh5wY&mnU#|%(1?5 z_VdD*;%lR~b^YM6jW1koSWs4HA1+siKwmPeibA!}!IO2D;|b)07wIPPLay%WRoj!c z#+Q@kX_T{Ef^A0_5|*-8kCPv%6e@PAB^e8>nf7XoW_0>-u=u_M&4xUTt0nMreeT-q zex)=MSHB{8hA7kqVGN(vTiIpd*(#!V@Ftf1Q2=WSOI#97g(UO?C*R~2d6J-kBIXT&I9+}*0}kX9ZncFQTx8XNg*sYE|-xNHM8qFke&DTLfs_u zMNV#B9o^~MO5+>iAX4b!HDhz3;gj+J!@uPWWASggyH@k|_x=P9`b*xm( zB)~OCo2-X5x;8x#cK|0a-J&IRjy+PV*>?Zx{Z;MvP&V^V!Nk2U9}s`*HbwC<$?oVZi#aku z@7r@WIU2hLZ^Lt;P+LdeW`got#Kdrm6kWMNZdor@ArJ{W#GRyJnKP>AX;o$sk5YKA zdS;nN%7r2!pD=a=8`9{vXYgD;a1@FWOl355Ax5hfCEqFgzGUW54|5|p(_9B)b6eaGf)Qlc{r-$eCvZf1TJL$nW~r8FA=ere(|qh zAFTP7eadp_pW=P#=g%#E6|c%a++^fPAfWi*$@aUfN867fZWnt~>IFb`KLzwAemEXP zja|Fd5ITfrJS2d!K&4H&Y|eb{uOAx`E3>p_@o}q^rM}`h%BJ90loVDm=nm} zW}`Od1L?4{LiQL{lz_yvNz!ZG5}R?ptKm3TcCoqjm!!L&5l)U&I^T>Exy66884TpzEUc$MIDC3syny>k&?B|Z&%~Wgx z-{w~c6f81%G8BA`5Ty1J?tCumb9ISwmY(Rhp#n153L=79;Z01+$u z`uEcmNJjjkfrLD)O8Aj>u}-^Mrce`5;lnKap z7Hf3V8lbDOvPKOW;IH}ezC9G*Hq_7?EXn(8Vs-`2JqeU7s~A4A7sn?o z!_So072C@=+rH$A?~zY@Cv7G#CtW6!3RZg% z{Nm)XiG3$L*pi5rCoQl7{g?Yzbe3g?`hziW*hQ_GRol(T6o-Cm;SGlj_I6-?vS%1j z9*|D&3n@;Ub}5K1L?ttAGv)Se+uf4{UF02$z8DnFP!rxTyw1p@=StBc%cJocik1dV z2l3){oK!1KPnD+3s6-X-YAUW6M$^t={|b+DFU5D;^icoyqiZ|0YzvwC$75p^`l)m> zEuw*SUJo{`D%u(=IlK9iWDv>VB0*hgti}ywsgJC{Q~5OgRF#_*7_Lux3Mu@SUh5e*W%vf!ribi|Cx08!J?B-ja$yLFacc^|}EjPiq zfm`CQDν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 Date: Wed, 4 Apr 2018 15:22:33 -0700 Subject: [PATCH 58/81] Import translations. DO NOT MERGE Change-Id: I541d5ba543c96278c8fa956faeef4ffd13b2953b Auto-generated-cl: translation import --- quickstep/res/values-af/strings.xml | 2 ++ quickstep/res/values-am/strings.xml | 2 ++ quickstep/res/values-ar/strings.xml | 2 ++ quickstep/res/values-az/strings.xml | 2 ++ quickstep/res/values-b+sr+Latn/strings.xml | 2 ++ quickstep/res/values-be/strings.xml | 6 +++--- quickstep/res/values-bg/strings.xml | 2 ++ quickstep/res/values-bn/strings.xml | 2 ++ quickstep/res/values-bs/strings.xml | 2 ++ quickstep/res/values-ca/strings.xml | 2 ++ quickstep/res/values-cs/strings.xml | 2 ++ quickstep/res/values-da/strings.xml | 6 +++--- quickstep/res/values-de/strings.xml | 6 +++--- quickstep/res/values-el/strings.xml | 2 ++ quickstep/res/values-en-rAU/strings.xml | 2 ++ quickstep/res/values-en-rGB/strings.xml | 2 ++ quickstep/res/values-en-rIN/strings.xml | 2 ++ quickstep/res/values-es-rUS/strings.xml | 6 +++--- quickstep/res/values-es/strings.xml | 6 +++--- quickstep/res/values-et/strings.xml | 6 +++--- quickstep/res/values-eu/strings.xml | 6 +++--- quickstep/res/values-fa/strings.xml | 2 ++ quickstep/res/values-fi/strings.xml | 6 +++--- quickstep/res/values-fr-rCA/strings.xml | 6 +++--- quickstep/res/values-fr/strings.xml | 6 +++--- quickstep/res/values-gl/strings.xml | 2 ++ quickstep/res/values-gu/strings.xml | 2 ++ quickstep/res/values-hi/strings.xml | 2 ++ quickstep/res/values-hr/strings.xml | 2 ++ quickstep/res/values-hu/strings.xml | 6 +++--- quickstep/res/values-hy/strings.xml | 6 +++--- quickstep/res/values-in/strings.xml | 2 ++ quickstep/res/values-it/strings.xml | 6 +++--- quickstep/res/values-iw/strings.xml | 6 +++--- quickstep/res/values-ja/strings.xml | 6 +++--- quickstep/res/values-ka/strings.xml | 6 +++--- quickstep/res/values-kk/strings.xml | 6 +++--- quickstep/res/values-km/strings.xml | 2 ++ quickstep/res/values-kn/strings.xml | 2 ++ quickstep/res/values-ko/strings.xml | 6 +++--- quickstep/res/values-ky/strings.xml | 6 +++--- quickstep/res/values-lo/strings.xml | 6 +++--- quickstep/res/values-lt/strings.xml | 2 ++ quickstep/res/values-lv/strings.xml | 2 ++ quickstep/res/values-mk/strings.xml | 2 ++ quickstep/res/values-ml/strings.xml | 2 ++ quickstep/res/values-mn/strings.xml | 6 +++--- quickstep/res/values-mr/strings.xml | 6 +++--- quickstep/res/values-ms/strings.xml | 6 +++--- quickstep/res/values-my/strings.xml | 2 ++ quickstep/res/values-nb/strings.xml | 6 +++--- quickstep/res/values-ne/strings.xml | 2 ++ quickstep/res/values-nl/strings.xml | 6 +++--- quickstep/res/values-pa/strings.xml | 6 +++--- quickstep/res/values-pl/strings.xml | 6 +++--- quickstep/res/values-pt-rPT/strings.xml | 2 ++ quickstep/res/values-pt/strings.xml | 2 ++ quickstep/res/values-ro/strings.xml | 2 ++ quickstep/res/values-ru/strings.xml | 2 ++ quickstep/res/values-si/strings.xml | 2 ++ quickstep/res/values-sk/strings.xml | 2 ++ quickstep/res/values-sl/strings.xml | 2 ++ quickstep/res/values-sq/strings.xml | 2 ++ quickstep/res/values-sr/strings.xml | 2 ++ quickstep/res/values-sv/strings.xml | 6 +++--- quickstep/res/values-sw/strings.xml | 2 ++ quickstep/res/values-te/strings.xml | 2 ++ quickstep/res/values-th/strings.xml | 2 ++ quickstep/res/values-tl/strings.xml | 2 ++ quickstep/res/values-tr/strings.xml | 2 ++ quickstep/res/values-uk/strings.xml | 2 ++ quickstep/res/values-ur/strings.xml | 2 ++ quickstep/res/values-uz/strings.xml | 6 +++--- quickstep/res/values-vi/strings.xml | 6 +++--- quickstep/res/values-zh-rCN/strings.xml | 6 +++--- quickstep/res/values-zh-rHK/strings.xml | 4 +++- quickstep/res/values-zh-rTW/strings.xml | 2 ++ quickstep/res/values-zu/strings.xml | 2 ++ 78 files changed, 188 insertions(+), 94 deletions(-) diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index 6196894191..fa8f9dc589 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -24,4 +24,6 @@ "Swiep van onder af op om programme te wissel" "Oorsig" "Geen onlangse items nie" + + diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 5a892ad9f8..d14e06c9e0 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -24,4 +24,6 @@ "መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ" "ማጠቃለያ" "ምንም የቅርብ ጊዜ ንጥሎች የሉም" + + diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index 3d83fcb7da..8efffd26db 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -24,4 +24,6 @@ "التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات" "نظرة عامة" "ليست هناك عناصر تم استخدامها مؤخرًا" + + diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index bede24b6fe..a832f9aa0e 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -24,4 +24,6 @@ "Tətbiqləri dəyişmək üçün aşağıdan yuxarı doğru sürüşdürün" "İcmal" "Son elementlər yoxdur" + + diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index b2f8b7ab08..ba44830be4 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -24,4 +24,6 @@ "Prevucite nagore da biste prešli na drugu aplikaciju" "Pregled" "Nema nedavnih stavki" + + diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml index b03f4a1d53..df55803afe 100644 --- a/quickstep/res/values-be/strings.xml +++ b/quickstep/res/values-be/strings.xml @@ -22,8 +22,8 @@ "Падзяліць экран" "Замацаваць" "Для пераключэння праграм правядзіце па экране пальцам знізу ўверх" - - - + "Агляд" + "Няма новых элементаў" + diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index bbf73c06ae..c46245c83b 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -24,4 +24,6 @@ "Прекарайте пръст нагоре от долната част, за да превключите между приложенията" "Общ преглед" "Няма скорошни елементи" + + diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml index 4c7e79b641..9080072316 100644 --- a/quickstep/res/values-bn/strings.xml +++ b/quickstep/res/values-bn/strings.xml @@ -26,4 +26,6 @@ + + diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index a6bbc24d62..7e61277d59 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -24,4 +24,6 @@ "Prevucite od dolje prema gore za promjenu aplikacije" "Pregled" "Nema nedavnih stavki" + + diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml index dc4aa935cd..ac77992132 100644 --- a/quickstep/res/values-ca/strings.xml +++ b/quickstep/res/values-ca/strings.xml @@ -26,4 +26,6 @@ + + diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index b6f99db3e0..e8c0cb055e 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -24,4 +24,6 @@ "Aplikace můžete přepínat přejetím zdola nahoru" "Přehled" "Žádné nedávné položky" + + diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml index f69bea50cf..6ddb31b364 100644 --- a/quickstep/res/values-da/strings.xml +++ b/quickstep/res/values-da/strings.xml @@ -22,8 +22,8 @@ "Delt skærm" "Fastgør" "Stryg opad fra bunden for at skifte apps" - - - + "Oversigt" + "Ingen nye elementer" + diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml index 6b9ffbbcc4..01c785e60a 100644 --- a/quickstep/res/values-de/strings.xml +++ b/quickstep/res/values-de/strings.xml @@ -22,8 +22,8 @@ "Bildschirm teilen" "Fixieren" "Zum Wechseln zwischen Apps vom unteren Bildschirmrand nach oben wischen" - - - + "Übersicht" + "Keine kürzlich verwendeten Elemente" + diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index bdee73b4d4..6b2a25f909 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -24,4 +24,6 @@ "Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών" "Επισκόπηση" "Δεν υπάρχουν πρόσφατα στοιχεία" + + diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml index 0a65f2fef7..402499e65d 100644 --- a/quickstep/res/values-en-rAU/strings.xml +++ b/quickstep/res/values-en-rAU/strings.xml @@ -24,4 +24,6 @@ "Swipe up from the bottom to switch apps" "Overview" "No recent items" + + diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index 0a65f2fef7..402499e65d 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -24,4 +24,6 @@ "Swipe up from the bottom to switch apps" "Overview" "No recent items" + + diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml index 0a65f2fef7..402499e65d 100644 --- a/quickstep/res/values-en-rIN/strings.xml +++ b/quickstep/res/values-en-rIN/strings.xml @@ -24,4 +24,6 @@ "Swipe up from the bottom to switch apps" "Overview" "No recent items" + + diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml index 5cb541b480..1b9f926dbb 100644 --- a/quickstep/res/values-es-rUS/strings.xml +++ b/quickstep/res/values-es-rUS/strings.xml @@ -22,8 +22,8 @@ "Pantalla dividida" "Fijar" "Desliza el dedo hacia arriba para cambiar de app" - - - + "Recientes" + "No hay elementos recientes" + diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index 1b526fda3d..c63f1d3ea5 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -22,8 +22,8 @@ "Dividir pantalla" "Fijar" "Desliza el dedo hacia arriba desde la parte inferior para cambiar de aplicación" - - - + "Aplicaciones recientes" + "No hay elementos recientes" + diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml index 5fc1c31d84..30199b91ca 100644 --- a/quickstep/res/values-et/strings.xml +++ b/quickstep/res/values-et/strings.xml @@ -22,8 +22,8 @@ "Jagatud ekraan" "Kinnita" "Rakenduste vahetamiseks pühkige alaosast üles" - - - + "Ülevaade" + "Hiljutisi üksusi pole" + diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml index ed10439e25..b6386cd48d 100644 --- a/quickstep/res/values-eu/strings.xml +++ b/quickstep/res/values-eu/strings.xml @@ -22,8 +22,8 @@ "Zatitu pantaila" "Ainguratu" "Aplikazioak aldatzeko, pasatu hatza pantailako behealdetik gora" - - - + "Ikuspegi orokorra" + "Ez dago azkenaldi honetako ezer" + diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index 75d2e7eaf3..52beadd791 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -24,4 +24,6 @@ "برای تغییر برنامه‌ها،‌ از پایین تند به بالا بکشید" "نمای کلی" "بدون موارد اخیر" + + diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml index 824d9b8169..a27a9cb497 100644 --- a/quickstep/res/values-fi/strings.xml +++ b/quickstep/res/values-fi/strings.xml @@ -22,8 +22,8 @@ "Jaettu näyttö" "Kiinnitä" "Vaihda sovellusta pyyhkäisemällä alareunasta ylös." - - - + "Viimeisimmät" + "Ei viimeaikaisia kohteita" + diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml index 94a09eb294..8a603e98ea 100644 --- a/quickstep/res/values-fr-rCA/strings.xml +++ b/quickstep/res/values-fr-rCA/strings.xml @@ -22,8 +22,8 @@ "Écran divisé" "Épingler" "Balayez l\'écran du bas vers le haut pour changer d\'application" - - - + "Aperçu" + "Aucun élément récent" + diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml index 1c88e33fd1..91922872c6 100644 --- a/quickstep/res/values-fr/strings.xml +++ b/quickstep/res/values-fr/strings.xml @@ -22,8 +22,8 @@ "Écran partagé" "Épingler" "Balayer l\'écran de bas en haut pour changer d\'application" - - - + "Aperçu" + "Aucun élément récent" + diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index 9c5c0ee832..25d3796b49 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -24,4 +24,6 @@ "Pasa o dedo cara arriba desde a parte inferior para cambiar de aplicacións" "Visión xeral" "Non hai elementos recentes" + + diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml index 9d3da8c262..f463e130c9 100644 --- a/quickstep/res/values-gu/strings.xml +++ b/quickstep/res/values-gu/strings.xml @@ -26,4 +26,6 @@ + + diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml index de1d086492..ee933d1bd0 100644 --- a/quickstep/res/values-hi/strings.xml +++ b/quickstep/res/values-hi/strings.xml @@ -26,4 +26,6 @@ + + diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index ab533618fa..a0b734f5ef 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -24,4 +24,6 @@ "Prijeđite prstom od dna prema gore da biste promijenili aplikaciju" "Pregled" "Nema nedavnih stavki" + + diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml index 5209dded26..8a465e2a3c 100644 --- a/quickstep/res/values-hu/strings.xml +++ b/quickstep/res/values-hu/strings.xml @@ -22,8 +22,8 @@ "Osztott képernyő" "Rögzítés" "Ha váltani szeretne az alkalmazások között, csúsztassa gyorsan az ujját a képernyő aljától felfelé" - - - + "Áttekintés" + "Nincsenek mostanában használt elemek" + diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml index fb03f671d8..fdfe81895e 100644 --- a/quickstep/res/values-hy/strings.xml +++ b/quickstep/res/values-hy/strings.xml @@ -22,8 +22,8 @@ "Տրոհել էկրանը" "Ամրացնել" "Սահեցրեք ներքևից վերև՝ մյուս հավելվածին անցնելու համար" - - - + "Ընդհանուր տեղեկություններ" + "Վերջին տարրեր չկան" + diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index 603ec5a0e2..786a10ccda 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -24,4 +24,6 @@ "Geser dari bawah ke atas untuk beralih aplikasi" "Ringkasan" "Tidak ada item baru-baru ini" + + diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml index b1064d7f4a..0da2251be2 100644 --- a/quickstep/res/values-it/strings.xml +++ b/quickstep/res/values-it/strings.xml @@ -22,8 +22,8 @@ "Schermo diviso" "Blocca" "Scorri verso l\'alto dalla parte inferiore per cambiare app" - - - + "Panoramica" + "Nessun elemento recente" + diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml index ab55dfc3fa..f7e8338781 100644 --- a/quickstep/res/values-iw/strings.xml +++ b/quickstep/res/values-iw/strings.xml @@ -22,8 +22,8 @@ "מסך מפוצל" "הצמדה" "יש להחליק כלפי מעלה מהחלק התחתון כדי לעבור בין אפליקציות" - - - + "מסכים אחרונים" + "אין פריטים אחרונים" + diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index a5ed5307f3..7e14d2c689 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -22,8 +22,8 @@ "分割画面" "固定" "アプリを切り替えるには、下から上にスワイプします" - - - + "概要" + "最近のアイテムはありません" + diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml index e845c88429..cf4c661d3d 100644 --- a/quickstep/res/values-ka/strings.xml +++ b/quickstep/res/values-ka/strings.xml @@ -22,8 +22,8 @@ "ეკრანის გაყოფა" "ჩამაგრება" "აპების გადასართავად გადაფურცლეთ ქვედა კიდედან ზემოთ" - - - + "მიმოხილვა" + "ბოლოს გამოყენებული ერთეულები არ არის" + diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml index f816fec609..f865a0405e 100644 --- a/quickstep/res/values-kk/strings.xml +++ b/quickstep/res/values-kk/strings.xml @@ -22,8 +22,8 @@ "Экранды бөлу" "Бекіту" "Қолданбалар арасында ауысу үшін төменнен жоғары қарай саусақпен сырғытыңыз" - - - + "Шолу" + "Соңғы элементтер жоқ" + diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index 5b1c55c5d5..a35ab26aad 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -24,4 +24,6 @@ "អូស​ពី​ក្រោម​ឡើង​លើ ដើម្បី​ប្ដូរ​កម្មវិធី" "ទិដ្ឋភាពរួម" "មិនមានធាតុថ្មីៗទេ" + + diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 303949100e..dc57df1d35 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -24,4 +24,6 @@ "ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ" "ಅವಲೋಕನ" "ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ" + + diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml index b4287705b2..36fd122d73 100644 --- a/quickstep/res/values-ko/strings.xml +++ b/quickstep/res/values-ko/strings.xml @@ -22,8 +22,8 @@ "화면 분할" "고정" "아래에서 위로 스와이프하여 앱을 전환합니다." - - - + "최근 사용" + "최근 항목이 없습니다." + diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml index e04d2ed369..060a8dd21c 100644 --- a/quickstep/res/values-ky/strings.xml +++ b/quickstep/res/values-ky/strings.xml @@ -22,8 +22,8 @@ "Экранды бөлүү" "Кадап коюу" "Колдонмолорду которуштуруу үчүн экранды төмөндөн жогору карай сүрүңүз" - - - + "Сереп салуу" + "Акыркы колдонмолор жок" + diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml index 2411871d3f..1abb856d97 100644 --- a/quickstep/res/values-lo/strings.xml +++ b/quickstep/res/values-lo/strings.xml @@ -22,8 +22,8 @@ "ແບ່ງໜ້າຈໍ" "ປັກໝຸດ" "ປັດຂຶ້ນຈາກລຸ່ມສຸດເພື່ອສະຫຼັບແອັບ" - - - + "ພາບຮວມ" + "ບໍ່ມີລາຍການຫຼ້າສຸດ" + diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index 06eeb5a8f9..0c09a94500 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -24,4 +24,6 @@ "Perbraukite aukštyn iš apačios, kad perjungtumėte programas" "Apžvalga" "Nėra jokių naujausių elementų" + + diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index 6b869917b5..72d1cb575d 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -24,4 +24,6 @@ "Lai pārslēgtu lietotnes, velciet augšup no apakšdaļas." "Pārskats" "Nav nesenu vienumu." + + diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index a86a2a2e28..06bf5d0c11 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -24,4 +24,6 @@ "Повлечете нагоре од дното за да ги смените апликациите" "Преглед" "Нема неодамнешни ставки" + + diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 4ff880cfd2..b936906560 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -24,4 +24,6 @@ "ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക" "അവലോകനം" "സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല" + + diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index e4253f60d2..8b92214916 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -22,8 +22,8 @@ "Дэлгэцийг хуваах" "Тогтоох" "Аппыг сэлгэхийн тулд доороос дээш шударна уу" - - - + "Тойм" + "Сүүлийн үеийн зүйл алга" + diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml index 5b9a621c46..596792d103 100644 --- a/quickstep/res/values-mr/strings.xml +++ b/quickstep/res/values-mr/strings.xml @@ -22,8 +22,8 @@ "विभाजित स्क्रीन" "पिन करा" "अ‍ॅप्स स्विच करण्यासाठी तळापासून वर स्वाइप करा" - - - + "अवलोकन" + "कोणतेही अलीकडील आयटम नाहीत" + diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml index a13b7bb981..336aaf6594 100644 --- a/quickstep/res/values-ms/strings.xml +++ b/quickstep/res/values-ms/strings.xml @@ -22,8 +22,8 @@ "Skrin pisah" "Semat" "Leret ke atas dari bawah untuk menukar apl" - - - + "Ikhtisar" + "Tiada item terbaharu" + diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index c7662a86b9..d71e5fc93f 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -24,4 +24,6 @@ "အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ" "အနှစ်ချုပ်" "မကြာမီကဖွင့်ထားသည်များ မရှိပါ" + + diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml index 3547ba4e35..504f43ae80 100644 --- a/quickstep/res/values-nb/strings.xml +++ b/quickstep/res/values-nb/strings.xml @@ -22,8 +22,8 @@ "Delt skjerm" "Fest" "Sveip opp fra bunnen for å bytte app" - - - + "Oversikt" + "Ingen nylige elementer" + diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index 73738f5024..7500213890 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -24,4 +24,6 @@ "अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्" "परिदृश्य" "हालसालैको कुनै पनि वस्तु छैन" + + diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml index a8e092a50e..2ba24a6e28 100644 --- a/quickstep/res/values-nl/strings.xml +++ b/quickstep/res/values-nl/strings.xml @@ -22,8 +22,8 @@ "Gesplitst scherm" "Vastzetten" "Veeg omhoog vanaf de onderkant om tussen apps te wisselen" - - - + "Overzicht" + "Geen recente items" + diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index 38d7499340..fbcb60cd6f 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -22,8 +22,8 @@ "ਸਪਲਿਟ ਸਕ੍ਰੀਨ" "ਪਿੰਨ ਕਰੋ" "ਐਪਾਂ ਵਿੱਚ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ" - - - + "ਰੂਪ-ਰੇਖਾ" + "ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ" + diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml index 5a730ac1db..1ad7070bd5 100644 --- a/quickstep/res/values-pl/strings.xml +++ b/quickstep/res/values-pl/strings.xml @@ -22,8 +22,8 @@ "Podziel ekran" "Przypnij" "Przesuń palcem z dołu ekranu, by przełączać aplikacje" - - - + "Przegląd" + "Brak ostatnich elementów" + diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml index f2496a02ac..a63d32998d 100644 --- a/quickstep/res/values-pt-rPT/strings.xml +++ b/quickstep/res/values-pt-rPT/strings.xml @@ -24,4 +24,6 @@ "Deslize rapidamente para cima a partir da parte inferior para alternar entre aplicações." "Vista geral" "Nenhum item recente" + + diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index cc54aa7b2a..05d20e08e0 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -24,4 +24,6 @@ "Deslize de baixo para cima para alternar entre apps" "Visão geral" "Nenhum item recente" + + diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml index c4d2338081..4264370f40 100644 --- a/quickstep/res/values-ro/strings.xml +++ b/quickstep/res/values-ro/strings.xml @@ -24,4 +24,6 @@ "Glisați de jos în sus pentru a schimba aplicațiile" "Recente" "Niciun element recent" + + diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index a0de61a146..47ddff53ca 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -24,4 +24,6 @@ "Чтобы переключить приложение, проведите по экрану снизу вверх" "Обзор" "Недавних приложений нет." + + diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index ad291165e3..a9b1493bb5 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -24,4 +24,6 @@ "යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න" "දළ විශ්ලේෂණය" "මෑත අයිතම නැත" + + diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index 4e7467f1e8..fe028554f6 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -24,4 +24,6 @@ "Aplikácie môžete prepínať potiahnutím prstom zdola nahor" "Prehľad" "Žiadne nedávne položky" + + diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index d19b69f49e..72d52a51c6 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -24,4 +24,6 @@ "Če želite preklopiti med aplikacijami, z dna zaslona s prstom povlecite navzgor" "Pregled" "Ni nedavnih elementov" + + diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index e9dc7769c2..954342cd93 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -24,4 +24,6 @@ "Rrëshqit larg nga poshtë për të ndryshuar aplikacionet" "Përmbledhja" "Nuk ka asnjë artikull të fundit" + + diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index ad10d4c998..51a9586e64 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -24,4 +24,6 @@ "Превуците нагоре да бисте прешли на другу апликацију" "Преглед" "Нема недавних ставки" + + diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml index e7bdf190b2..266cf60ef7 100644 --- a/quickstep/res/values-sv/strings.xml +++ b/quickstep/res/values-sv/strings.xml @@ -22,8 +22,8 @@ "Delad skärm" "Fäst" "Växla mellan appar genom att svepa uppåt från nederkanten" - - - + "Översikt" + "Listan med de senaste åtgärderna är tom" + diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index 7f453c67a0..e85fa45bbd 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -24,4 +24,6 @@ "Telezesha kidole juu kuanzia chini ili ubadilishe programu" "Muhtasari" "Hakuna vipengee vya hivi karibuni" + + diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 543b225a5b..108f35042c 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -24,4 +24,6 @@ "యాప్‌లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి" "అవలోకనం" "ఇటీవలి అంశాలు ఏవీ లేవు" + + diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 92fa179f1b..80f91b087b 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -24,4 +24,6 @@ "เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป" "ภาพรวม" "ไม่มีรายการล่าสุด" + + diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index 136cee41de..b28e04e72d 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -24,4 +24,6 @@ "Mag-swipe pataas mula sa ibaba para lumipat ng app" "Overview" "Walang kamakailang item" + + diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index 542f26243f..1399353561 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -24,4 +24,6 @@ "Uygulamaları değiştirmek için alttan yukarı kaydırın" "Genel bakış" "Yeni öğe yok" + + diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 44c04c3e25..929bbe795d 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -24,4 +24,6 @@ "Щоб переходити між додатками, проводьте пальцем знизу вгору" "Огляд" "Немає нещодавніх додатків" + + diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml index 341ab0d5c3..0271fe4d24 100644 --- a/quickstep/res/values-ur/strings.xml +++ b/quickstep/res/values-ur/strings.xml @@ -26,4 +26,6 @@ + + diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml index bb6edb77c4..91e11d3dca 100644 --- a/quickstep/res/values-uz/strings.xml +++ b/quickstep/res/values-uz/strings.xml @@ -22,8 +22,8 @@ "Ekranni ikkiga ajratish" "Mahkamlash" "Ilovalarni almashtirish uchun pastdan yuqoriga suring" - - - + "Nazar" + "Yaqinda ishlatilgan ilovalar yo‘q" + diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 2241f022af..809517a58b 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -22,8 +22,8 @@ "Chia đôi màn hình" "Ghim" "Vuốt từ dưới lên để chuyển đổi ứng dụng" - - - + "Tổng quan" + "Không có mục gần đây nào" + diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml index 77b6432b40..a44dd2db06 100644 --- a/quickstep/res/values-zh-rCN/strings.xml +++ b/quickstep/res/values-zh-rCN/strings.xml @@ -22,8 +22,8 @@ "分屏" "固定" "从屏幕底部向上滑动即可切换应用" - - - + "概览" + "近期没有任何内容" + diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index bdf27ede9b..3879bc568e 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -22,6 +22,8 @@ "分割畫面" "固定" "從螢幕底部向上快速滑動,即可切換應用程式" - "總覽" + "概覽" "最近沒有任何項目" + + diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index b7528cafd9..f275168f67 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -24,4 +24,6 @@ "從畫面底部向上滑動以切換應用程式" "總覽" "最近沒有任何項目" + + diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index e43e98677d..206718eff8 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -24,4 +24,6 @@ "Swayiphela phezulu kusukela phansi ukuze ushintshe izinhlelo zokusebenza" "Buka konke" "Azikho izinto zakamuva" + + From 8da28f50105f8fdb55b9dfe66df6f86e893108f0 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 4 Apr 2018 15:23:10 -0700 Subject: [PATCH 59/81] Fix quick scrub transition from home We were snapping to page 0, which is a no-op but interferes with the state transition. Change-Id: I85b39a26c513e63686ad176ac851711b466d3df3 --- .../src/com/android/quickstep/QuickScrubController.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 275fd29022..fd089b5927 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -138,9 +138,8 @@ public class QuickScrubController implements OnAlarmListener { } public void snapToNextTaskIfAvailable() { - if (mInQuickScrub && mRecentsView.getChildCount() > 0) { - int toPage = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1; - mRecentsView.snapToPage(toPage, QUICK_SCRUB_START_DURATION); + if (!mStartedFromHome && mInQuickScrub && mRecentsView.getChildCount() > 0) { + mRecentsView.snapToPage(mRecentsView.getNextPage() + 1, QUICK_SCRUB_START_DURATION); } } From 7296dc19b9248739fb1d89b2470263781b7b5425 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 4 Apr 2018 17:29:54 -0700 Subject: [PATCH 60/81] Fix crash when launching translucent activities. Bug: 77604451 Change-Id: I618d98a437e36e872faee2bbb07d9b8bf8779dbd --- .../com/android/launcher3/LauncherAppTransitionManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index dffe641d86..73cff299eb 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -154,8 +154,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag mLauncher.getStateManager().setCurrentAnimation(anim); if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) { + anim.play(getIconAnimator(v)); if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) { - anim.play(getIconAnimator(v)); anim.play(getLauncherContentAnimator(false /* show */)); } anim.play(getWindowAnimators(v, targetCompats)); From 83bf457aaad9ba96fa5e5ae98c3434cb7559fe60 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 5 Apr 2018 10:16:21 -0700 Subject: [PATCH 61/81] Fixing crash when starting transparent activities StateManager was setting the transition lenght to 0 when a workspace state transtion was being created as part of launching a transparent activity. Bug: 77635129 Change-Id: Ie9f40138d9b1387ba880bca0fbf130a4872e8733 --- .../launcher3/LauncherAppTransitionManagerImpl.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 73cff299eb..af81a59004 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -149,11 +149,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { AnimatorSet anim = new AnimatorSet(); - // Set the state animation first so that any state listeners are called - // before our internal listeners. - mLauncher.getStateManager().setCurrentAnimation(anim); + if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) { + // Set the state animation first so that any state listeners are called + // before our internal listeners. + mLauncher.getStateManager().setCurrentAnimation(anim); + anim.play(getIconAnimator(v)); if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) { anim.play(getLauncherContentAnimator(false /* show */)); @@ -284,6 +286,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets)); target.play(launcherAnim); + + // Set the current animation first, before adding windowAnimEndListener. Setting current + // animation adds some listeners which need to be called before windowAnimEndListener + // (the ordering of listeners matter in this case). + mLauncher.getStateManager().setCurrentAnimation(target); target.addListener(windowAnimEndListener); return true; } From 2c430b34cbab3d156c93d90b457b70e3a869ec0a Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Wed, 4 Apr 2018 14:45:21 -0700 Subject: [PATCH 62/81] Avoid duplicate accessibility announcement upon switching to -1st page Since -1st window already has accessible description, no need to announce "Page X of Y" for it. Bug: 74210311 Test: Manual Change-Id: I5cbfd763778b5f7049be732a750df4501b5419e0 --- src/com/android/launcher3/PagedView.java | 16 +++++++++++++--- src/com/android/launcher3/Workspace.java | 20 +++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 79993c11aa..15bf76da50 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -424,6 +424,13 @@ public abstract class PagedView extends ViewGrou return computeScrollHelper(true); } + protected void announcePageForAccessibility() { + if (isAccessibilityEnabled(getContext())) { + // Notify the user when the page changes + announceForAccessibility(getCurrentPageDescription()); + } + } + protected boolean computeScrollHelper(boolean shouldInvalidate) { if (mScroller.computeScrollOffset()) { // Don't bother scrolling if the page does not need to be moved @@ -452,9 +459,8 @@ public abstract class PagedView extends ViewGrou pageEndTransition(); } - if (isAccessibilityEnabled(getContext())) { - // Notify the user when the page changes - announceForAccessibility(getCurrentPageDescription()); + if (canAnnouncePageDescription()) { + announcePageForAccessibility(); } } return false; @@ -1535,6 +1541,10 @@ public abstract class PagedView extends ViewGrou return getCurrentPageDescription(); } + protected boolean canAnnouncePageDescription() { + return true; + } + protected String getCurrentPageDescription() { return getContext().getString(R.string.default_scroll_format, getNextPage() + 1, getChildCount()); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 34ae8ea3d1..a39d273e95 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1143,30 +1143,37 @@ public class Workspace extends PagedView * The overlay scroll is being controlled locally, just update our overlay effect */ public void onOverlayScrollChanged(float scroll) { - if (Float.compare(scroll, 1f) == 0) { if (!mOverlayShown) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.LEFT, ContainerType.WORKSPACE, 0); } mOverlayShown = true; + // Not announcing the overlay page for accessibility since it announces itself. } else if (Float.compare(scroll, 0f) == 0) { if (mOverlayShown) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.RIGHT, ContainerType.WORKSPACE, -1); + } else if (Float.compare(mOverlayTranslation, 0f) != 0) { + // When arriving to 0 overscroll from non-zero overscroll, announce page for + // accessibility since default announcements were disabled while in overscroll + // state. + // Not doing this if mOverlayShown because in that case the accessibility service + // will announce the launcher window description upon regaining focus after + // switching from the overlay screen. + announcePageForAccessibility(); } mOverlayShown = false; tryRunOverlayCallback(); } + float offset = 0f; - float slip = 0f; scroll = Math.max(scroll - offset, 0); scroll = Math.min(1, scroll / (1 - offset)); float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(scroll); float transX = mLauncher.getDragLayer().getMeasuredWidth() * scroll; - transX *= 1 - slip; if (mIsRtl) { transX = -transX; @@ -3344,6 +3351,13 @@ public class Workspace extends PagedView ? mLauncher.getDeviceProfile().widthPx : getMeasuredWidth(); } + @Override + protected boolean canAnnouncePageDescription() { + // Disable announcements while overscrolling potentially to overlay screen because if we end + // up on the overlay screen, it will take care of announcing itself. + return Float.compare(mOverlayTranslation, 0f) == 0; + } + @Override protected String getCurrentPageDescription() { int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; From ff8699e41186f6139e184df887af1d44b676603e Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Thu, 15 Mar 2018 23:48:46 +0000 Subject: [PATCH 63/81] Revert "Re-enabling Widgets in Launcher3Go" This reverts commit 2eb7f0a34bb201eb229f179579c430ebbe874f6e. Bug: 74039047 Test: Manual tests Change-Id: Ifa38f7b1b805d781fbfc63cd71b01609f0a85d9e --- Android.mk | 2 + go/AndroidManifest.xml | 53 +++++++++++++++ go/res/drawable/ic_widget.xml | 25 +++++++ go/res/layout/widget_cell_content.xml | 66 +++++++++++++++++++ go/res/values-af/strings.xml | 26 ++++++++ go/res/values-am/strings.xml | 26 ++++++++ go/res/values-ar/strings.xml | 26 ++++++++ go/res/values-az/strings.xml | 26 ++++++++ go/res/values-b+sr+Latn/strings.xml | 26 ++++++++ go/res/values-be/strings.xml | 26 ++++++++ go/res/values-bg/strings.xml | 26 ++++++++ go/res/values-bn/strings.xml | 26 ++++++++ go/res/values-bs/strings.xml | 26 ++++++++ go/res/values-ca/strings.xml | 26 ++++++++ go/res/values-cs/strings.xml | 26 ++++++++ go/res/values-da/strings.xml | 26 ++++++++ go/res/values-de/strings.xml | 26 ++++++++ go/res/values-el/strings.xml | 26 ++++++++ go/res/values-en-rAU/strings.xml | 26 ++++++++ go/res/values-en-rGB/strings.xml | 26 ++++++++ go/res/values-en-rIN/strings.xml | 26 ++++++++ go/res/values-es-rUS/strings.xml | 26 ++++++++ go/res/values-es/strings.xml | 26 ++++++++ go/res/values-et/strings.xml | 26 ++++++++ go/res/values-eu/strings.xml | 26 ++++++++ go/res/values-fa/strings.xml | 26 ++++++++ go/res/values-fi/strings.xml | 26 ++++++++ go/res/values-fr-rCA/strings.xml | 26 ++++++++ go/res/values-fr/strings.xml | 26 ++++++++ go/res/values-gl/strings.xml | 26 ++++++++ go/res/values-gu/strings.xml | 26 ++++++++ go/res/values-hi/strings.xml | 26 ++++++++ go/res/values-hr/strings.xml | 26 ++++++++ go/res/values-hu/strings.xml | 26 ++++++++ go/res/values-hy/strings.xml | 26 ++++++++ go/res/values-in/strings.xml | 26 ++++++++ go/res/values-is/strings.xml | 26 ++++++++ go/res/values-it/strings.xml | 26 ++++++++ go/res/values-iw/strings.xml | 26 ++++++++ go/res/values-ja/strings.xml | 26 ++++++++ go/res/values-ka/strings.xml | 26 ++++++++ go/res/values-kk/strings.xml | 26 ++++++++ go/res/values-km/strings.xml | 26 ++++++++ go/res/values-kn/strings.xml | 26 ++++++++ go/res/values-ko/strings.xml | 26 ++++++++ go/res/values-ky/strings.xml | 26 ++++++++ go/res/values-lo/strings.xml | 26 ++++++++ go/res/values-lt/strings.xml | 26 ++++++++ go/res/values-lv/strings.xml | 26 ++++++++ go/res/values-mk/strings.xml | 26 ++++++++ go/res/values-ml/strings.xml | 26 ++++++++ go/res/values-mn/strings.xml | 26 ++++++++ go/res/values-mr/strings.xml | 26 ++++++++ go/res/values-ms/strings.xml | 26 ++++++++ go/res/values-my/strings.xml | 26 ++++++++ go/res/values-nb/strings.xml | 26 ++++++++ go/res/values-ne/strings.xml | 26 ++++++++ go/res/values-nl/strings.xml | 26 ++++++++ go/res/values-pa/strings.xml | 26 ++++++++ go/res/values-pl/strings.xml | 26 ++++++++ go/res/values-pt-rPT/strings.xml | 26 ++++++++ go/res/values-pt/strings.xml | 26 ++++++++ go/res/values-ro/strings.xml | 26 ++++++++ go/res/values-ru/strings.xml | 26 ++++++++ go/res/values-si/strings.xml | 26 ++++++++ go/res/values-sk/strings.xml | 26 ++++++++ go/res/values-sl/strings.xml | 26 ++++++++ go/res/values-sq/strings.xml | 26 ++++++++ go/res/values-sr/strings.xml | 26 ++++++++ go/res/values-sv/strings.xml | 26 ++++++++ go/res/values-sw/strings.xml | 26 ++++++++ go/res/values-ta/strings.xml | 26 ++++++++ go/res/values-te/strings.xml | 26 ++++++++ go/res/values-th/strings.xml | 26 ++++++++ go/res/values-tl/strings.xml | 26 ++++++++ go/res/values-tr/strings.xml | 26 ++++++++ go/res/values-uk/strings.xml | 26 ++++++++ go/res/values-ur/strings.xml | 26 ++++++++ go/res/values-uz/strings.xml | 26 ++++++++ go/res/values-vi/strings.xml | 26 ++++++++ go/res/values-zh-rCN/strings.xml | 26 ++++++++ go/res/values-zh-rHK/strings.xml | 26 ++++++++ go/res/values-zh-rTW/strings.xml | 26 ++++++++ go/res/values-zu/strings.xml | 26 ++++++++ go/res/values/strings.xml | 33 ++++++++++ .../launcher3/config/FeatureFlags.java | 1 + 86 files changed, 2260 insertions(+) create mode 100644 go/AndroidManifest.xml create mode 100644 go/res/drawable/ic_widget.xml create mode 100644 go/res/layout/widget_cell_content.xml create mode 100644 go/res/values-af/strings.xml create mode 100644 go/res/values-am/strings.xml create mode 100644 go/res/values-ar/strings.xml create mode 100644 go/res/values-az/strings.xml create mode 100644 go/res/values-b+sr+Latn/strings.xml create mode 100644 go/res/values-be/strings.xml create mode 100644 go/res/values-bg/strings.xml create mode 100644 go/res/values-bn/strings.xml create mode 100644 go/res/values-bs/strings.xml create mode 100644 go/res/values-ca/strings.xml create mode 100644 go/res/values-cs/strings.xml create mode 100644 go/res/values-da/strings.xml create mode 100644 go/res/values-de/strings.xml create mode 100644 go/res/values-el/strings.xml create mode 100644 go/res/values-en-rAU/strings.xml create mode 100644 go/res/values-en-rGB/strings.xml create mode 100644 go/res/values-en-rIN/strings.xml create mode 100644 go/res/values-es-rUS/strings.xml create mode 100644 go/res/values-es/strings.xml create mode 100644 go/res/values-et/strings.xml create mode 100644 go/res/values-eu/strings.xml create mode 100644 go/res/values-fa/strings.xml create mode 100644 go/res/values-fi/strings.xml create mode 100644 go/res/values-fr-rCA/strings.xml create mode 100644 go/res/values-fr/strings.xml create mode 100644 go/res/values-gl/strings.xml create mode 100644 go/res/values-gu/strings.xml create mode 100644 go/res/values-hi/strings.xml create mode 100644 go/res/values-hr/strings.xml create mode 100644 go/res/values-hu/strings.xml create mode 100644 go/res/values-hy/strings.xml create mode 100644 go/res/values-in/strings.xml create mode 100644 go/res/values-is/strings.xml create mode 100644 go/res/values-it/strings.xml create mode 100644 go/res/values-iw/strings.xml create mode 100644 go/res/values-ja/strings.xml create mode 100644 go/res/values-ka/strings.xml create mode 100644 go/res/values-kk/strings.xml create mode 100644 go/res/values-km/strings.xml create mode 100644 go/res/values-kn/strings.xml create mode 100644 go/res/values-ko/strings.xml create mode 100644 go/res/values-ky/strings.xml create mode 100644 go/res/values-lo/strings.xml create mode 100644 go/res/values-lt/strings.xml create mode 100644 go/res/values-lv/strings.xml create mode 100644 go/res/values-mk/strings.xml create mode 100644 go/res/values-ml/strings.xml create mode 100644 go/res/values-mn/strings.xml create mode 100644 go/res/values-mr/strings.xml create mode 100644 go/res/values-ms/strings.xml create mode 100644 go/res/values-my/strings.xml create mode 100644 go/res/values-nb/strings.xml create mode 100644 go/res/values-ne/strings.xml create mode 100644 go/res/values-nl/strings.xml create mode 100644 go/res/values-pa/strings.xml create mode 100644 go/res/values-pl/strings.xml create mode 100644 go/res/values-pt-rPT/strings.xml create mode 100644 go/res/values-pt/strings.xml create mode 100644 go/res/values-ro/strings.xml create mode 100644 go/res/values-ru/strings.xml create mode 100644 go/res/values-si/strings.xml create mode 100644 go/res/values-sk/strings.xml create mode 100644 go/res/values-sl/strings.xml create mode 100644 go/res/values-sq/strings.xml create mode 100644 go/res/values-sr/strings.xml create mode 100644 go/res/values-sv/strings.xml create mode 100644 go/res/values-sw/strings.xml create mode 100644 go/res/values-ta/strings.xml create mode 100644 go/res/values-te/strings.xml create mode 100644 go/res/values-th/strings.xml create mode 100644 go/res/values-tl/strings.xml create mode 100644 go/res/values-tr/strings.xml create mode 100644 go/res/values-uk/strings.xml create mode 100644 go/res/values-ur/strings.xml create mode 100644 go/res/values-uz/strings.xml create mode 100644 go/res/values-vi/strings.xml create mode 100644 go/res/values-zh-rCN/strings.xml create mode 100644 go/res/values-zh-rHK/strings.xml create mode 100644 go/res/values-zh-rTW/strings.xml create mode 100644 go/res/values-zu/strings.xml create mode 100644 go/res/values/strings.xml diff --git a/Android.mk b/Android.mk index 256d95d0a6..0dc7ff1113 100644 --- a/Android.mk +++ b/Android.mk @@ -113,6 +113,8 @@ LOCAL_FULL_LIBS_MANIFEST_FILES := \ $(LOCAL_PATH)/AndroidManifest.xml \ $(LOCAL_PATH)/AndroidManifest-common.xml +LOCAL_MANIFEST_FILE := go/AndroidManifest.xml + LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.* include $(BUILD_PACKAGE) diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml new file mode 100644 index 0000000000..fbaf981d33 --- /dev/null +++ b/go/AndroidManifest.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + diff --git a/go/res/drawable/ic_widget.xml b/go/res/drawable/ic_widget.xml new file mode 100644 index 0000000000..53368760ee --- /dev/null +++ b/go/res/drawable/ic_widget.xml @@ -0,0 +1,25 @@ + + + + diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml new file mode 100644 index 0000000000..49506d9bec --- /dev/null +++ b/go/res/layout/widget_cell_content.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/go/res/values-af/strings.xml b/go/res/values-af/strings.xml new file mode 100644 index 0000000000..10ac473c1f --- /dev/null +++ b/go/res/values-af/strings.xml @@ -0,0 +1,26 @@ + + + + + "Raak en hou om \'n kortpad op te tel." + "Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge." + "Kortpaaie" + "%1$s-kortpaaie" + diff --git a/go/res/values-am/strings.xml b/go/res/values-am/strings.xml new file mode 100644 index 0000000000..b3b253f423 --- /dev/null +++ b/go/res/values-am/strings.xml @@ -0,0 +1,26 @@ + + + + + "አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ" + "አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።" + "አቋራጮች" + "%1$s አቋራጮች" + diff --git a/go/res/values-ar/strings.xml b/go/res/values-ar/strings.xml new file mode 100644 index 0000000000..2b3b80746f --- /dev/null +++ b/go/res/values-ar/strings.xml @@ -0,0 +1,26 @@ + + + + + "المس مع الاستمرار لاختيار اختصار." + "يمكنك النقر نقرًا مزدوجًا مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة." + "الاختصارات" + "اختصارات %1$s" + diff --git a/go/res/values-az/strings.xml b/go/res/values-az/strings.xml new file mode 100644 index 0000000000..c4b8cb7801 --- /dev/null +++ b/go/res/values-az/strings.xml @@ -0,0 +1,26 @@ + + + + + "Qısayolu seçmək üçün toxunub saxlayın." + "Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin." + "Qısayollar" + "%1$s qısayolları" + diff --git a/go/res/values-b+sr+Latn/strings.xml b/go/res/values-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..0da5699410 --- /dev/null +++ b/go/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,26 @@ + + + + + "Dodirnite i zadržite da biste izabrali prečicu." + "Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje." + "Prečice" + "Prečice za %1$s" + diff --git a/go/res/values-be/strings.xml b/go/res/values-be/strings.xml new file mode 100644 index 0000000000..4189e35fa0 --- /dev/null +++ b/go/res/values-be/strings.xml @@ -0,0 +1,26 @@ + + + + + "Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго." + "Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні." + "Ярлыкі" + "Ярлыкі %1$s" + diff --git a/go/res/values-bg/strings.xml b/go/res/values-bg/strings.xml new file mode 100644 index 0000000000..1b85992d99 --- /dev/null +++ b/go/res/values-bg/strings.xml @@ -0,0 +1,26 @@ + + + + + "Докоснете и задръжте за избор на пряк път." + "Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия." + "Преки пътища" + "Преки пътища за %1$s" + diff --git a/go/res/values-bn/strings.xml b/go/res/values-bn/strings.xml new file mode 100644 index 0000000000..c56c925a29 --- /dev/null +++ b/go/res/values-bn/strings.xml @@ -0,0 +1,26 @@ + + + + + "কোনও শর্টকাট বেছে নিতে টাচ করে ধরে রাখুন।" + "কোনও শর্টকাট বেছে নিতে ডাবল ট্যাপ করে ধরে রাখুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন।" + "শর্টকাট" + "%1$s এর শর্টকাট" + diff --git a/go/res/values-bs/strings.xml b/go/res/values-bs/strings.xml new file mode 100644 index 0000000000..7042468b47 --- /dev/null +++ b/go/res/values-bs/strings.xml @@ -0,0 +1,26 @@ + + + + + "Dodirnite i držite da uzmete prečicu." + "Dvaput dodirnite i držite da uzmete prečicu ili koristite prilagođene akcije." + "Prečice" + "Prečice aplikacije %1$s" + diff --git a/go/res/values-ca/strings.xml b/go/res/values-ca/strings.xml new file mode 100644 index 0000000000..3b5c3f7b56 --- /dev/null +++ b/go/res/values-ca/strings.xml @@ -0,0 +1,26 @@ + + + + + "Mantén premuda una drecera per seleccionar-la." + "Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades." + "Dreceres" + "Dreceres de l\'aplicació %1$s" + diff --git a/go/res/values-cs/strings.xml b/go/res/values-cs/strings.xml new file mode 100644 index 0000000000..e4018f2c0f --- /dev/null +++ b/go/res/values-cs/strings.xml @@ -0,0 +1,26 @@ + + + + + "Zkratku vyberete podržením." + "Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce." + "Zkratky" + "Zkratky aplikace %1$s" + diff --git a/go/res/values-da/strings.xml b/go/res/values-da/strings.xml new file mode 100644 index 0000000000..821d36a7da --- /dev/null +++ b/go/res/values-da/strings.xml @@ -0,0 +1,26 @@ + + + + + "Hold en genvej nede for at samle den op." + "Tryk to gange, og hold en genvej nede for at samle den op og bruge tilpassede handlinger." + "Genveje" + "%1$s-genveje" + diff --git a/go/res/values-de/strings.xml b/go/res/values-de/strings.xml new file mode 100644 index 0000000000..43a1b3a9e1 --- /dev/null +++ b/go/res/values-de/strings.xml @@ -0,0 +1,26 @@ + + + + + "Doppeltippen und halten, um eine Verknüpfung auszuwählen." + "Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen." + "Verknüpfungen" + "%1$s-Verknüpfungen" + diff --git a/go/res/values-el/strings.xml b/go/res/values-el/strings.xml new file mode 100644 index 0000000000..ae59907d16 --- /dev/null +++ b/go/res/values-el/strings.xml @@ -0,0 +1,26 @@ + + + + + "Αγγίξτε παρατεταμένα για να σηκώσετε μια συντόμευση." + "Πατήσετε δύο φορές παρατεταμένα για να σηκώσετε μια συντόμευση ή για να χρησιμοποιήσετε προσαρμοσμένες ενέργειες." + "Συντομεύσεις" + "Συντομεύσεις %1$s" + diff --git a/go/res/values-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml new file mode 100644 index 0000000000..2ee2c26457 --- /dev/null +++ b/go/res/values-en-rAU/strings.xml @@ -0,0 +1,26 @@ + + + + + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "Shortcuts" + "%1$s shortcuts" + diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml new file mode 100644 index 0000000000..2ee2c26457 --- /dev/null +++ b/go/res/values-en-rGB/strings.xml @@ -0,0 +1,26 @@ + + + + + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "Shortcuts" + "%1$s shortcuts" + diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml new file mode 100644 index 0000000000..2ee2c26457 --- /dev/null +++ b/go/res/values-en-rIN/strings.xml @@ -0,0 +1,26 @@ + + + + + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "Shortcuts" + "%1$s shortcuts" + diff --git a/go/res/values-es-rUS/strings.xml b/go/res/values-es-rUS/strings.xml new file mode 100644 index 0000000000..5212c035d3 --- /dev/null +++ b/go/res/values-es-rUS/strings.xml @@ -0,0 +1,26 @@ + + + + + "Mantén presionado para elegir un acceso directo." + "Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas." + "Accesos directos" + "Accesos directos de %1$s" + diff --git a/go/res/values-es/strings.xml b/go/res/values-es/strings.xml new file mode 100644 index 0000000000..3ae45889cf --- /dev/null +++ b/go/res/values-es/strings.xml @@ -0,0 +1,26 @@ + + + + + "Mantén pulsado el acceso directo que quieras." + "Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas." + "Accesos directos" + "Accesos directos de %1$s" + diff --git a/go/res/values-et/strings.xml b/go/res/values-et/strings.xml new file mode 100644 index 0000000000..2513e65a33 --- /dev/null +++ b/go/res/values-et/strings.xml @@ -0,0 +1,26 @@ + + + + + "Otsetee valimiseks puudutage seda pikalt." + "Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks." + "Otseteed" + "Rakenduse %1$s otseteed" + diff --git a/go/res/values-eu/strings.xml b/go/res/values-eu/strings.xml new file mode 100644 index 0000000000..9949ef091d --- /dev/null +++ b/go/res/values-eu/strings.xml @@ -0,0 +1,26 @@ + + + + + "Eduki sakatuta lasterbide bat aukeratzeko." + "Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko." + "Lasterbideak" + "%1$s aplikazioaren lasterbidea" + diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml new file mode 100644 index 0000000000..f1584d9ff7 --- /dev/null +++ b/go/res/values-fa/strings.xml @@ -0,0 +1,26 @@ + + + + + "برای انتخاب یک میان‌بر، لمس کنید و نگه‌دارید." + "برای انتخاب میان‌بر، دو ضربه سریع بزنید و نگه دارید یا از کنش‌های سفارشی استفاده کنید." + "میان‌برها" + "میان‌برهای %1$s" + diff --git a/go/res/values-fi/strings.xml b/go/res/values-fi/strings.xml new file mode 100644 index 0000000000..da9b0e1c42 --- /dev/null +++ b/go/res/values-fi/strings.xml @@ -0,0 +1,26 @@ + + + + + "Valitse pikakuvake painamalla sitä pitkään." + "Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään." + "Pikakuvakkeet" + "Kohteen %1$s pikakuvakkeet" + diff --git a/go/res/values-fr-rCA/strings.xml b/go/res/values-fr-rCA/strings.xml new file mode 100644 index 0000000000..c7fd6d6423 --- /dev/null +++ b/go/res/values-fr-rCA/strings.xml @@ -0,0 +1,26 @@ + + + + + "Maintenez un doigt sur le raccourci pour l\'ajouter" + "Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées." + "Raccourcis" + "Raccourcis : %1$s" + diff --git a/go/res/values-fr/strings.xml b/go/res/values-fr/strings.xml new file mode 100644 index 0000000000..238fe73d75 --- /dev/null +++ b/go/res/values-fr/strings.xml @@ -0,0 +1,26 @@ + + + + + "Appui prolongé pour sélectionner raccourci." + "Appuyez 2 fois et maintenez pression pour sélectionner raccourci ou utilisez actions personnalisées." + "Raccourcis" + "Raccourcis %1$s" + diff --git a/go/res/values-gl/strings.xml b/go/res/values-gl/strings.xml new file mode 100644 index 0000000000..31621d5c2c --- /dev/null +++ b/go/res/values-gl/strings.xml @@ -0,0 +1,26 @@ + + + + + "Mantén premido un atallo para seleccionalo." + "Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas." + "Atallos" + "Atallos da aplicación %1$s" + diff --git a/go/res/values-gu/strings.xml b/go/res/values-gu/strings.xml new file mode 100644 index 0000000000..bdb549ff7f --- /dev/null +++ b/go/res/values-gu/strings.xml @@ -0,0 +1,26 @@ + + + + + "એક શૉર્ટકટ ચૂંટવા ટૅપ કરી રાખો." + "એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરી રાખો." + "શૉર્ટકટ" + "%1$s શૉર્ટકટ" + diff --git a/go/res/values-hi/strings.xml b/go/res/values-hi/strings.xml new file mode 100644 index 0000000000..2c1650a0dd --- /dev/null +++ b/go/res/values-hi/strings.xml @@ -0,0 +1,26 @@ + + + + + "शॉर्टकट चुनने के लिए छूकर रखें." + "शॉर्टकट चुनने के लिए दो बार छूएं और कुछ देर दबाएं रखें या अपने मुताबिक कार्रवाइयों का इस्तेमाल करें." + "शॉर्टकट" + "%1$s शॉर्टकट" + diff --git a/go/res/values-hr/strings.xml b/go/res/values-hr/strings.xml new file mode 100644 index 0000000000..fccdeb59d7 --- /dev/null +++ b/go/res/values-hr/strings.xml @@ -0,0 +1,26 @@ + + + + + "Dodirnite i zadržite kako biste podigli prečac." + "Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama." + "Prečaci" + "Prečaci za aplikaciju %1$s" + diff --git a/go/res/values-hu/strings.xml b/go/res/values-hu/strings.xml new file mode 100644 index 0000000000..369c22745a --- /dev/null +++ b/go/res/values-hu/strings.xml @@ -0,0 +1,26 @@ + + + + + "Felvételhez tartsa nyomva a parancsikont." + "Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket." + "Parancsikonok" + "%1$s-parancsikonok" + diff --git a/go/res/values-hy/strings.xml b/go/res/values-hy/strings.xml new file mode 100644 index 0000000000..4747f6df35 --- /dev/null +++ b/go/res/values-hy/strings.xml @@ -0,0 +1,26 @@ + + + + + "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։" + "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:" + "Դյուրանցումներ" + "%1$s դյուրանցումներ" + diff --git a/go/res/values-in/strings.xml b/go/res/values-in/strings.xml new file mode 100644 index 0000000000..c8b9da306d --- /dev/null +++ b/go/res/values-in/strings.xml @@ -0,0 +1,26 @@ + + + + + "Tap lama untuk memilih pintasan." + "Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus." + "Pintasan" + "Pintasan %1$s" + diff --git a/go/res/values-is/strings.xml b/go/res/values-is/strings.xml new file mode 100644 index 0000000000..b8bb923746 --- /dev/null +++ b/go/res/values-is/strings.xml @@ -0,0 +1,26 @@ + + + + + "Haltu fingri á flýtileið til að grípa hana." + "Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir." + "Flýtileiðir" + "%1$s flýtileiðir" + diff --git a/go/res/values-it/strings.xml b/go/res/values-it/strings.xml new file mode 100644 index 0000000000..bc5d99863d --- /dev/null +++ b/go/res/values-it/strings.xml @@ -0,0 +1,26 @@ + + + + + "Tocca e tieni premuto per scegliere la scorciatoia" + "Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate." + "Scorciatoie" + "Scorciatoie di %1$s" + diff --git a/go/res/values-iw/strings.xml b/go/res/values-iw/strings.xml new file mode 100644 index 0000000000..f541d4d316 --- /dev/null +++ b/go/res/values-iw/strings.xml @@ -0,0 +1,26 @@ + + + + + "כדי להוסיף קיצור דרך, מקישים עליו פעמיים ומחזיקים." + "כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, מקישים על קיצור הדרך פעמיים ומחזיקים." + "קיצורי דרך" + "קיצורי דרך לאפליקציה %1$s" + diff --git a/go/res/values-ja/strings.xml b/go/res/values-ja/strings.xml new file mode 100644 index 0000000000..8f02d7f4eb --- /dev/null +++ b/go/res/values-ja/strings.xml @@ -0,0 +1,26 @@ + + + + + "ショートカットを追加するには押し続けます。" + "ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。" + "ショートカット" + "「%1$s」のショートカット" + diff --git a/go/res/values-ka/strings.xml b/go/res/values-ka/strings.xml new file mode 100644 index 0000000000..1b46534788 --- /dev/null +++ b/go/res/values-ka/strings.xml @@ -0,0 +1,26 @@ + + + + + "შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად." + "ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად." + "მალსახმობები" + "%1$s-ის მალსახმობები" + diff --git a/go/res/values-kk/strings.xml b/go/res/values-kk/strings.xml new file mode 100644 index 0000000000..e909818afc --- /dev/null +++ b/go/res/values-kk/strings.xml @@ -0,0 +1,26 @@ + + + + + "Таңбашаны таңдау үшін оны түртіп, ұстап тұрыңыз." + "Таңбашаны таңдау немесе арнаулы әрекеттерді пайдалану үшін екі рет түртіп, ұстап тұрыңыз." + "Таңбашалар" + "%1$s таңбаша" + diff --git a/go/res/values-km/strings.xml b/go/res/values-km/strings.xml new file mode 100644 index 0000000000..40082a4b9d --- /dev/null +++ b/go/res/values-km/strings.xml @@ -0,0 +1,26 @@ + + + + + "ប៉ះ ហើយចុចឲ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ។" + "ប៉ះពីរដង ហើយចុចឱ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។" + "ផ្លូវកាត់" + "ផ្លូវកាត់សម្រាប់ %1$s" + diff --git a/go/res/values-kn/strings.xml b/go/res/values-kn/strings.xml new file mode 100644 index 0000000000..9c121fd294 --- /dev/null +++ b/go/res/values-kn/strings.xml @@ -0,0 +1,26 @@ + + + + + "ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ." + "ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ." + "ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು" + "%1$s ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು" + diff --git a/go/res/values-ko/strings.xml b/go/res/values-ko/strings.xml new file mode 100644 index 0000000000..60f925e36b --- /dev/null +++ b/go/res/values-ko/strings.xml @@ -0,0 +1,26 @@ + + + + + "바로가기를 선택하려면 길게 터치하세요." + "바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다." + "바로가기" + "%1$s 바로가기" + diff --git a/go/res/values-ky/strings.xml b/go/res/values-ky/strings.xml new file mode 100644 index 0000000000..4c7e973cef --- /dev/null +++ b/go/res/values-ky/strings.xml @@ -0,0 +1,26 @@ + + + + + "Кыска жолду тандоо үчүн басып туруңуз." + "Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз." + "Кыска жолдор" + "%1$s кыска жол" + diff --git a/go/res/values-lo/strings.xml b/go/res/values-lo/strings.xml new file mode 100644 index 0000000000..7864884acc --- /dev/null +++ b/go/res/values-lo/strings.xml @@ -0,0 +1,26 @@ + + + + + "ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ." + "ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ." + "ປຸ່ມລັດ" + "ປຸ່ມລັດ %1$s" + diff --git a/go/res/values-lt/strings.xml b/go/res/values-lt/strings.xml new file mode 100644 index 0000000000..8f49032cfb --- /dev/null +++ b/go/res/values-lt/strings.xml @@ -0,0 +1,26 @@ + + + + + "Dukart pal. ir palaik., kad pasir. spart. klav." + "Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus." + "Spartieji klavišai" + "„%1$s“ spartieji klavišai" + diff --git a/go/res/values-lv/strings.xml b/go/res/values-lv/strings.xml new file mode 100644 index 0000000000..04315ebaa0 --- /dev/null +++ b/go/res/values-lv/strings.xml @@ -0,0 +1,26 @@ + + + + + "Lai izvēlētos saīsni, pieskarieties un turiet to." + "Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to vai arī veiciet pielāgotas darbības." + "Saīsnes" + "Lietotnes %1$s saīsnes" + diff --git a/go/res/values-mk/strings.xml b/go/res/values-mk/strings.xml new file mode 100644 index 0000000000..52d66b5e28 --- /dev/null +++ b/go/res/values-mk/strings.xml @@ -0,0 +1,26 @@ + + + + + "Допрете двапати и задржете за да изберете кратенка." + "Допрете двапати и задржете за да изберете кратенка или да користите приспособени дејства." + "Кратенки" + "Кратенки за %1$s" + diff --git a/go/res/values-ml/strings.xml b/go/res/values-ml/strings.xml new file mode 100644 index 0000000000..b3c12e16e1 --- /dev/null +++ b/go/res/values-ml/strings.xml @@ -0,0 +1,26 @@ + + + + + "ഒരു കുറുക്കുവഴി ചേർക്കുന്നതിന് അത് സ്‌പർശിച്ച് പിടിക്കുക." + "ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക." + "കുറുക്കുവഴികൾ" + "%1$s കുറുക്കുവഴികൾ" + diff --git a/go/res/values-mn/strings.xml b/go/res/values-mn/strings.xml new file mode 100644 index 0000000000..c89dfd1bdc --- /dev/null +++ b/go/res/values-mn/strings.xml @@ -0,0 +1,26 @@ + + + + + "Товчлол авах бол удаан дарна уу." + "Товчлол авах болон тохируулсан үйлдлийг ашиглахын тулд хоёр товшоод хүлээнэ үү." + "Товчлол" + "%1$s-н товчлол" + diff --git a/go/res/values-mr/strings.xml b/go/res/values-mr/strings.xml new file mode 100644 index 0000000000..2c767b4f19 --- /dev/null +++ b/go/res/values-mr/strings.xml @@ -0,0 +1,26 @@ + + + + + "शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा." + "शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा." + "शॉर्टकट" + "%1$s शॉर्टकट" + diff --git a/go/res/values-ms/strings.xml b/go/res/values-ms/strings.xml new file mode 100644 index 0000000000..42add9a197 --- /dev/null +++ b/go/res/values-ms/strings.xml @@ -0,0 +1,26 @@ + + + + + "Sentuh & tahan untuk mengambil pintasan." + "Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai." + "Pintasan" + "Pintasan %1$s" + diff --git a/go/res/values-my/strings.xml b/go/res/values-my/strings.xml new file mode 100644 index 0000000000..5784df63bf --- /dev/null +++ b/go/res/values-my/strings.xml @@ -0,0 +1,26 @@ + + + + + "လက်ကွက်ဖြတ်လမ်းတစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ" + "လက်ကွက်ဖြတ်လမ်းကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန်နှစ်ချက်တို့ပြီး ဖိထားပါ။" + "ဖြတ်လမ်းလင့်ခ်များ" + "%1$s ဖြတ်လမ်းလင့်ခ်များ" + diff --git a/go/res/values-nb/strings.xml b/go/res/values-nb/strings.xml new file mode 100644 index 0000000000..2a5ffb6e7c --- /dev/null +++ b/go/res/values-nb/strings.xml @@ -0,0 +1,26 @@ + + + + + "Trykk og hold for å velge en snarvei." + "Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger." + "Snarveier" + "%1$s-snarveier" + diff --git a/go/res/values-ne/strings.xml b/go/res/values-ne/strings.xml new file mode 100644 index 0000000000..0be0375f3a --- /dev/null +++ b/go/res/values-ne/strings.xml @@ -0,0 +1,26 @@ + + + + + "कुनै सटकर्ट छनौट गर्न छोइराख्नुहोस्।" + "कुनै सर्टकट छनौट गर्न दुईपटक ट्याप गरेर होल्ड गर्नुहोस् वा रोजेका कारबाहीहरू प्रयोग गर्नुहोस्।" + "सर्टकटहरू" + "%1$s सर्टकटहरू" + diff --git a/go/res/values-nl/strings.xml b/go/res/values-nl/strings.xml new file mode 100644 index 0000000000..5bcd016b4a --- /dev/null +++ b/go/res/values-nl/strings.xml @@ -0,0 +1,26 @@ + + + + + "Tik en houd vast om snelkoppeling toe te voegen." + "Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken." + "Snelkoppelingen" + "%1$s-snelkoppelingen" + diff --git a/go/res/values-pa/strings.xml b/go/res/values-pa/strings.xml new file mode 100644 index 0000000000..c7e4abf3a8 --- /dev/null +++ b/go/res/values-pa/strings.xml @@ -0,0 +1,26 @@ + + + + + "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।" + "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।" + "ਸ਼ਾਰਟਕੱਟ" + "%1$s ਸ਼ਾਰਟਕੱਟ" + diff --git a/go/res/values-pl/strings.xml b/go/res/values-pl/strings.xml new file mode 100644 index 0000000000..45a1dc2cac --- /dev/null +++ b/go/res/values-pl/strings.xml @@ -0,0 +1,26 @@ + + + + + "Kliknij i przytrzymaj, by wybrać skrót." + "Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych." + "Skróty" + "%1$s – skróty" + diff --git a/go/res/values-pt-rPT/strings.xml b/go/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000000..7a75a05456 --- /dev/null +++ b/go/res/values-pt-rPT/strings.xml @@ -0,0 +1,26 @@ + + + + + "Toque sem soltar para escolher um atalho." + "Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas." + "Atalhos" + "Atalhos da aplicação %1$s" + diff --git a/go/res/values-pt/strings.xml b/go/res/values-pt/strings.xml new file mode 100644 index 0000000000..53bbfc41a6 --- /dev/null +++ b/go/res/values-pt/strings.xml @@ -0,0 +1,26 @@ + + + + + "Toque e segure para selecionar um atalho." + "Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas." + "Atalhos" + "Atalhos do app %1$s" + diff --git a/go/res/values-ro/strings.xml b/go/res/values-ro/strings.xml new file mode 100644 index 0000000000..75d1796b57 --- /dev/null +++ b/go/res/values-ro/strings.xml @@ -0,0 +1,26 @@ + + + + + "Atingeți și țineți apăsat pentru a selecta o comandă rapidă." + "Atingeți de două ori și țineți apăsat pentru comandă rapidă sau folosiți acțiuni personalizate." + "Comenzi rapide" + "Comenzi rapide pentru %1$s" + diff --git a/go/res/values-ru/strings.xml b/go/res/values-ru/strings.xml new file mode 100644 index 0000000000..9c5c8cd340 --- /dev/null +++ b/go/res/values-ru/strings.xml @@ -0,0 +1,26 @@ + + + + + "Чтобы выбрать ярлык, нажмите на него и удерживайте." + "Чтобы выбрать ярлык или использовать специальные действия, нажмите на него дважды и не отпускайте." + "Ярлыки" + "%1$s: ярлыки" + diff --git a/go/res/values-si/strings.xml b/go/res/values-si/strings.xml new file mode 100644 index 0000000000..4b25c90b0b --- /dev/null +++ b/go/res/values-si/strings.xml @@ -0,0 +1,26 @@ + + + + + "කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න." + "විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න." + "කෙටි මං" + "කෙටි මං %1$s" + diff --git a/go/res/values-sk/strings.xml b/go/res/values-sk/strings.xml new file mode 100644 index 0000000000..fc02933734 --- /dev/null +++ b/go/res/values-sk/strings.xml @@ -0,0 +1,26 @@ + + + + + "Skratku pridáte pridržaním." + "Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií." + "Skratky" + "Skratky aplikácie %1$s" + diff --git a/go/res/values-sl/strings.xml b/go/res/values-sl/strings.xml new file mode 100644 index 0000000000..6ecedfb166 --- /dev/null +++ b/go/res/values-sl/strings.xml @@ -0,0 +1,26 @@ + + + + + "Pridržite bližnjico, da jo izberete." + "Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri." + "Bližnjice" + "Bližnjice za %1$s" + diff --git a/go/res/values-sq/strings.xml b/go/res/values-sq/strings.xml new file mode 100644 index 0000000000..bb74db6b55 --- /dev/null +++ b/go/res/values-sq/strings.xml @@ -0,0 +1,26 @@ + + + + + "Prek dhe mbaj prekur për të zgjedhur një shkurtore." + "Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara." + "Shkurtoret" + "%1$s shkurtore" + diff --git a/go/res/values-sr/strings.xml b/go/res/values-sr/strings.xml new file mode 100644 index 0000000000..0b9aea2f9a --- /dev/null +++ b/go/res/values-sr/strings.xml @@ -0,0 +1,26 @@ + + + + + "Додирните и задржите да бисте изабрали пречицу." + "Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње." + "Пречице" + "Пречице за %1$s" + diff --git a/go/res/values-sv/strings.xml b/go/res/values-sv/strings.xml new file mode 100644 index 0000000000..c3f434c276 --- /dev/null +++ b/go/res/values-sv/strings.xml @@ -0,0 +1,26 @@ + + + + + "Tryck länge om du vill ta upp en genväg." + "Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder." + "Genvägar" + "Genvägar för %1$s" + diff --git a/go/res/values-sw/strings.xml b/go/res/values-sw/strings.xml new file mode 100644 index 0000000000..13c12e4a6c --- /dev/null +++ b/go/res/values-sw/strings.xml @@ -0,0 +1,26 @@ + + + + + "Gusa na ushikilie ili uchague njia ya mkato." + "Gusa mara mbili na ushikilie ile uchague njia ya mkato au utumie vitendo maalum." + "Njia za mkato" + "Njia za mkato za %1$s" + diff --git a/go/res/values-ta/strings.xml b/go/res/values-ta/strings.xml new file mode 100644 index 0000000000..50059b65f9 --- /dev/null +++ b/go/res/values-ta/strings.xml @@ -0,0 +1,26 @@ + + + + + "குறுக்குவழியைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்." + "குறுக்குவழியை சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்." + "குறுக்குவழிகள்" + "%1$s குறுக்குவழிகள்" + diff --git a/go/res/values-te/strings.xml b/go/res/values-te/strings.xml new file mode 100644 index 0000000000..0bdf743342 --- /dev/null +++ b/go/res/values-te/strings.xml @@ -0,0 +1,26 @@ + + + + + "సత్వరమార్గాన్ని ఎంచుకోవడానికి తాకి & నొక్కి ఉంచండి." + "సత్వరమార్గాన్ని ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి &ఉంచండి." + "సత్వరమార్గాలు" + "%1$s సత్వరమార్గాలు" + diff --git a/go/res/values-th/strings.xml b/go/res/values-th/strings.xml new file mode 100644 index 0000000000..e73d89fb0e --- /dev/null +++ b/go/res/values-th/strings.xml @@ -0,0 +1,26 @@ + + + + + "แตะค้างไว้เพื่อเลือกทางลัด" + "แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง" + "ทางลัด" + "ทางลัด %1$s" + diff --git a/go/res/values-tl/strings.xml b/go/res/values-tl/strings.xml new file mode 100644 index 0000000000..8f44ec5742 --- /dev/null +++ b/go/res/values-tl/strings.xml @@ -0,0 +1,26 @@ + + + + + "Pindutin nang matagal upang kumuha ng shortcut." + "I-double tap nang matagal upang kumuha ng shortcut o gumamit ng mga custom na pagkilos." + "Mga Shortcut" + "Mga shortcut sa %1$s" + diff --git a/go/res/values-tr/strings.xml b/go/res/values-tr/strings.xml new file mode 100644 index 0000000000..f0f3cce6d1 --- /dev/null +++ b/go/res/values-tr/strings.xml @@ -0,0 +1,26 @@ + + + + + "Kısayol seçmek için dokunun ve basılı tutun." + "Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun." + "Kısayollar" + "%1$s kısayolları" + diff --git a/go/res/values-uk/strings.xml b/go/res/values-uk/strings.xml new file mode 100644 index 0000000000..8d1f58395b --- /dev/null +++ b/go/res/values-uk/strings.xml @@ -0,0 +1,26 @@ + + + + + "Натисніть і утримуйте, щоб вибрати ярлик." + "Двічі натисніть і утримуйте, щоб вибрати ярлик, або виконайте іншу дію." + "Ярлики" + "Ярлики додатка %1$s" + diff --git a/go/res/values-ur/strings.xml b/go/res/values-ur/strings.xml new file mode 100644 index 0000000000..46bd823d8e --- /dev/null +++ b/go/res/values-ur/strings.xml @@ -0,0 +1,26 @@ + + + + + "کوئی شارٹ کٹ منتخب کرنے کیلئے ٹچ کریں اور دبائے رکھیں۔" + "کوئی شارٹ کٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔" + "شارٹ کٹس" + "%1$s شارٹ کٹس" + diff --git a/go/res/values-uz/strings.xml b/go/res/values-uz/strings.xml new file mode 100644 index 0000000000..318bc15722 --- /dev/null +++ b/go/res/values-uz/strings.xml @@ -0,0 +1,26 @@ + + + + + "Yorliqni tanlab olish uchun bosib turing." + "Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning." + "Yorliqlar" + "%1$s ilovasi yorliqlari" + diff --git a/go/res/values-vi/strings.xml b/go/res/values-vi/strings.xml new file mode 100644 index 0000000000..1197619c57 --- /dev/null +++ b/go/res/values-vi/strings.xml @@ -0,0 +1,26 @@ + + + + + "Chạm và giữ để chọn lối tắt." + "Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh." + "Lối tắt" + "Lối tắt %1$s" + diff --git a/go/res/values-zh-rCN/strings.xml b/go/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..57351d37f5 --- /dev/null +++ b/go/res/values-zh-rCN/strings.xml @@ -0,0 +1,26 @@ + + + + + "触摸并按住快捷方式即可选择快捷方式。" + "点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。" + "快捷方式" + "%1$s快捷方式" + diff --git a/go/res/values-zh-rHK/strings.xml b/go/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000000..dea7749f68 --- /dev/null +++ b/go/res/values-zh-rHK/strings.xml @@ -0,0 +1,26 @@ + + + + + "按住捷徑即可選取捷徑。" + "扲兩下然後扲住就可以揀選捷徑,或者用自訂嘅操作。" + "捷徑" + "%1$s 捷徑" + diff --git a/go/res/values-zh-rTW/strings.xml b/go/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..07ae2ed5b4 --- /dev/null +++ b/go/res/values-zh-rTW/strings.xml @@ -0,0 +1,26 @@ + + + + + "按住捷徑即可選取。" + "輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。" + "捷徑" + "「%1$s」捷徑" + diff --git a/go/res/values-zu/strings.xml b/go/res/values-zu/strings.xml new file mode 100644 index 0000000000..e5051df1f1 --- /dev/null +++ b/go/res/values-zu/strings.xml @@ -0,0 +1,26 @@ + + + + + "Thinta futhi ubambe ukuze ukhethe isinqamuleli." + "Thepha kabulu futhi ubambe ukuze ukhethe isinqamuleli noma usebenzise izenzo zangokwezifiso." + "Izinqamuleli" + "%1$s izinqamuleli" + diff --git a/go/res/values/strings.xml b/go/res/values/strings.xml new file mode 100644 index 0000000000..8ef2e62430 --- /dev/null +++ b/go/res/values/strings.xml @@ -0,0 +1,33 @@ + + + + + + + Touch & hold to pick up a shortcut. + + Double-tap & hold to pick up a shortcut or use custom actions. + + Shortcuts + + + + %1$s shortcuts + + diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_flags/com/android/launcher3/config/FeatureFlags.java index f324fcd6c5..b11bb7c6aa 100644 --- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java +++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java @@ -24,5 +24,6 @@ public final class FeatureFlags extends BaseFlags { private FeatureFlags() {} // Features to control Launcher3Go behavior + public static final boolean GO_DISABLE_WIDGETS = true; public static final boolean LAUNCHER3_SPRING_ICONS = false; } From fcb7e19f67deaadbb535c074a445568ebb4ec898 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 5 Apr 2018 11:32:41 -0700 Subject: [PATCH 64/81] Close options popup when rebinding launcher. Bug: 77582012 Change-Id: I6707ca526c8c934f56b227288d2cbea7139ac41d --- src/com/android/launcher3/AbstractFloatingView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index f34cf0dc50..b0c5baf6b5 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -68,7 +68,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch // Type of popups which should be kept open during launcher rebind public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET - | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_OPTIONS_POPUP; + | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP; protected boolean mIsOpen; From c51493d2815cda49fa995209bac21b889e55881d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 5 Apr 2018 12:07:08 -0700 Subject: [PATCH 65/81] Don't let touches go through popup when notification is present Bug: 76139059 Change-Id: I7d39fbeb60e871eeadedb8a3ee1ef81dc4e2f47e --- src/com/android/launcher3/popup/PopupContainerWithArrow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 422a4ecd26..454fc7d404 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -129,7 +129,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, @Override public boolean onTouchEvent(MotionEvent ev) { if (mNotificationItemView != null) { - return mNotificationItemView.onTouchEvent(ev); + return mNotificationItemView.onTouchEvent(ev) || super.onTouchEvent(ev); } return super.onTouchEvent(ev); } From d3897cbab7f3f49fb388fe83fd7030ea14a73f83 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 5 Apr 2018 12:20:06 -0700 Subject: [PATCH 66/81] Parallax all apps up slightly as you swipe up from overview Change-Id: Ib587844ca8a5a61322902c5415eef19186062aa2 --- .../src/com/android/launcher3/uioverrides/AllAppsState.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java index 0e3d2a4bc2..d2f54874f5 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java @@ -89,9 +89,7 @@ public class AllAppsState extends LauncherState { @Override public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) { - // Keep the same transition properties as overview, so that we don't move around when - // transitioning to All Apps. - return LauncherState.OVERVIEW.getOverviewScaleAndTranslationYFactor(launcher); + return new float[] {1f, -0.2f}; } @Override From c9fa640ceecb02259e74cb034e32958d6f99cc52 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 5 Apr 2018 11:43:08 -0700 Subject: [PATCH 67/81] Update delete/uninstall/close icons. Bug: 77641054 Change-Id: I8fb7cc4ffe835de57d8104373816deffe77870d9 --- res/drawable/ic_close.xml | 2 +- res/drawable/ic_uninstall_no_shadow.xml | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/res/drawable/ic_close.xml b/res/drawable/ic_close.xml index fc9ed49e94..8b2f55fb32 100644 --- a/res/drawable/ic_close.xml +++ b/res/drawable/ic_close.xml @@ -19,5 +19,5 @@ android:viewportWidth="24.0"> + android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41z" /> \ No newline at end of file diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml index 2a86e1042d..37632d1a4b 100644 --- a/res/drawable/ic_uninstall_no_shadow.xml +++ b/res/drawable/ic_uninstall_no_shadow.xml @@ -21,6 +21,11 @@ android:tint="?android:attr/textColorPrimary" > + android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4H15z M17,19H7V6h10V19z" /> + + From 9054843a1fad9198fd70d8183d1305734dfd6395 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 4 Apr 2018 17:17:00 -0700 Subject: [PATCH 68/81] Simplifying fallback recents animation Instead of using WindowTransformSwipeHandler, keeping the launcher UI in place and just animating the window Change-Id: I4defce3a9745407523de651aeb28a37867567507 --- .../LauncherAppTransitionManagerImpl.java | 76 ++-- .../launcher3/LauncherInitListener.java | 43 ++- .../quickstep/ActivityControlHelper.java | 42 +- .../quickstep/OverviewCommandHelper.java | 358 +++++++----------- .../quickstep/RecentsActivityTracker.java | 14 + .../RecentsAnimationActivityOptions.java | 104 ----- .../WindowTransformSwipeHandler.java | 136 +------ .../quickstep/util/ClipAnimationHelper.java | 134 +++++++ .../util/RemoteAnimationProvider.java | 55 +++ .../views/LauncherLayoutListener.java | 5 + .../android/quickstep/views/RecentsView.java | 26 +- src/com/android/launcher3/Launcher.java | 3 +- 12 files changed, 439 insertions(+), 557 deletions(-) delete mode 100644 quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java create mode 100644 quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java create mode 100644 quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index af81a59004..a2567c885a 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -57,6 +57,7 @@ import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; +import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -106,7 +107,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private DeviceProfile mDeviceProfile; private View mFloatingView; - private RemoteAnimationRunnerCompat mRemoteAnimationOverride; + private RemoteAnimationProvider mRemoteAnimationProvider; private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() { @Override @@ -179,8 +180,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } - public void setRemoteAnimationOverride(RemoteAnimationRunnerCompat remoteAnimationOverride) { - mRemoteAnimationOverride = remoteAnimationOverride; + public void setRemoteAnimationProvider(RemoteAnimationProvider animationProvider) { + mRemoteAnimationProvider = animationProvider; } /** @@ -682,53 +683,34 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag */ private RemoteAnimationRunnerCompat getWallpaperOpenRunner() { return new LauncherAnimationRunner(mHandler) { - @Override - public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, - Runnable runnable) { - if (mLauncher.getStateManager().getState().overviewUi - && mRemoteAnimationOverride != null) { - // This transition is only used for the fallback activity and should not be - // managed here (but necessary to implement here since the defined remote - // animation currently takes precendence over the one defined in the activity - // options). - mRemoteAnimationOverride.onAnimationStart(targetCompats, runnable); - return; - } - super.onAnimationStart(targetCompats, runnable); - } - - @Override - public void onAnimationCancelled() { - if (mLauncher.getStateManager().getState().overviewUi - && mRemoteAnimationOverride != null) { - // This transition is only used for the fallback activity and should not be - // managed here (but necessary to implement here since the defined remote - // animation currently takes precendence over the one defined in the activity - // options). - mRemoteAnimationOverride.onAnimationCancelled(); - return; - } - super.onAnimationCancelled(); - } - @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - AnimatorSet anim = new AnimatorSet(); - anim.play(getClosingWindowAnimators(targetCompats)); - - // Normally, we run the launcher content animation when we are transitioning home, - // but if home is already visible, then we don't want to animate the contents of - // launcher unless we know that we are animating home as a result of the home button - // press with quickstep, which will result in launcher being started on touch down, - // prior to the animation home (and won't be in the targets list because it is - // already visible). In that case, we force invisibility on touch down, and only - // reset it after the animation to home is initialized. - if (launcherIsATargetWithMode(targetCompats, MODE_OPENING) - || mLauncher.isForceInvisible()) { - // Only register the content animation for cancellation when state changes - mLauncher.getStateManager().setCurrentAnimation(anim); - createLauncherResumeAnimation(anim); + AnimatorSet anim = null; + RemoteAnimationProvider provider = mRemoteAnimationProvider; + if (provider != null) { + anim = provider.createWindowAnimation(targetCompats); } + + if (anim == null) { + anim = new AnimatorSet(); + anim.play(getClosingWindowAnimators(targetCompats)); + + // Normally, we run the launcher content animation when we are transitioning + // home, but if home is already visible, then we don't want to animate the + // contents of launcher unless we know that we are animating home as a result + // of the home button press with quickstep, which will result in launcher being + // started on touch down, prior to the animation home (and won't be in the + // targets list because it is already visible). In that case, we force + // invisibility on touch down, and only reset it after the animation to home + // is initialized. + if (launcherIsATargetWithMode(targetCompats, MODE_OPENING) + || mLauncher.isForceInvisible()) { + // Only register the content animation for cancellation when state changes + mLauncher.getStateManager().setCurrentAnimation(anim); + createLauncherResumeAnimation(anim); + } + } + mLauncher.setForceInvisible(false); return anim; } diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index 0d1038a2d9..27f169834d 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -15,13 +15,16 @@ */ package com.android.launcher3; -import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK; - import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; import android.os.Build; +import android.os.Bundle; +import android.os.Handler; import com.android.launcher3.states.InternalStateHandler; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.util.RemoteAnimationProvider; import java.util.function.BiPredicate; @@ -30,15 +33,33 @@ public class LauncherInitListener extends InternalStateHandler implements Activi private final BiPredicate mOnInitListener; + private RemoteAnimationProvider mRemoteAnimationProvider; + public LauncherInitListener(BiPredicate onInitListener) { mOnInitListener = onInitListener; } @Override protected boolean init(Launcher launcher, boolean alreadyOnHome) { - // For the duration of the gesture, lock the screen orientation to ensure that we do not - // rotate mid-quickscrub - launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK); + if (mRemoteAnimationProvider != null) { + LauncherAppTransitionManagerImpl appTransitionManager = + (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager(); + + // Set a one-time animation provider. After the first call, this will get cleared. + // TODO: Probably also check the intended target id. + appTransitionManager.setRemoteAnimationProvider((targets) -> { + + // On the first call clear the reference. + appTransitionManager.setRemoteAnimationProvider(null); + RemoteAnimationProvider provider = mRemoteAnimationProvider; + mRemoteAnimationProvider = null; + + if (provider != null && launcher.getStateManager().getState().overviewUi) { + return provider.createWindowAnimation(targets); + } + return null; + }); + } return mOnInitListener.test(launcher, alreadyOnHome); } @@ -49,6 +70,18 @@ public class LauncherInitListener extends InternalStateHandler implements Activi @Override public void unregister() { + mRemoteAnimationProvider = null; clearReference(); } + + @Override + public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, + Context context, Handler handler, long duration) { + mRemoteAnimationProvider = animProvider; + + register(); + + Bundle options = animProvider.toActivityOptions(handler, duration).toBundle(); + context.startActivity(addToIntent(new Intent((intent))), options); + } } diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 3e96c4452e..d82b8f437c 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -22,7 +22,6 @@ import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.graphics.Rect; @@ -39,19 +38,17 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.quickstep.fallback.FallbackRecentsView; +import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.views.LauncherLayoutListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.AssistDataReceiver; import com.android.systemui.shared.system.RecentsAnimationListener; -import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import java.util.function.BiPredicate; @@ -85,9 +82,6 @@ public interface ActivityControlHelper { void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver, final RecentsAnimationListener remoteAnimationListener); - void startRecentsFromButton(Context context, Intent intent, - RecentsAnimationListener remoteAnimationListener); - @UiThread @Nullable RecentsView getVisibleRecentsView(); @@ -214,24 +208,6 @@ public interface ActivityControlHelper { intent, assistDataReceiver, remoteAnimationListener, null, null); } - @Override - public void startRecentsFromButton(Context context, Intent intent, - RecentsAnimationListener remoteAnimationListener) { - // We should use the remove animation for the fallback activity recents button case, - // it works better with PiP. In Launcher, we have already registered the remote - // animation definition, which takes priority over explicitly defined remote - // animations in the provided activity options when starting the activity, so we - // just register a remote animation factory to get a callback to handle this. - LauncherAppTransitionManagerImpl appTransitionManager = - (LauncherAppTransitionManagerImpl) getLauncher().getAppTransitionManager(); - appTransitionManager.setRemoteAnimationOverride(new RecentsAnimationActivityOptions( - remoteAnimationListener, () -> { - // Once the controller is finished, also reset the remote animation override - appTransitionManager.setRemoteAnimationOverride(null); - })); - context.startActivity(intent); - } - @Nullable @UiThread private Launcher getLauncher() { @@ -360,19 +336,6 @@ public interface ActivityControlHelper { intent, assistDataReceiver, remoteAnimationListener, null, null); } - @Override - public void startRecentsFromButton(Context context, Intent intent, - RecentsAnimationListener remoteAnimationListener) { - // We should use the remove animation for the fallback activity recents button case, - // it works better with PiP. For the fallback activity, we should not have registered - // the launcher app transition manager, so we should just start the remote animation here. - ActivityOptions options = ActivityOptionsCompat.makeRemoteAnimation( - new RemoteAnimationAdapterCompat( - new RecentsAnimationActivityOptions(remoteAnimationListener, null), - 10000, 10000)); - context.startActivity(intent, options.toBundle()); - } - @Nullable @Override public RecentsView getVisibleRecentsView() { @@ -403,5 +366,8 @@ public interface ActivityControlHelper { void register(); void unregister(); + + void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, + Context context, Handler handler, long duration); } } diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 8e59578a23..2fb4127258 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -16,68 +16,46 @@ package com.android.quickstep; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; -import android.animation.Animator; +import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.TargetApi; -import android.app.ActivityManager.RecentTaskInfo; -import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Build; -import android.os.Bundle; import android.os.SystemClock; -import android.os.UserHandle; -import android.support.annotation.UiThread; -import android.support.annotation.WorkerThread; -import android.util.SparseArray; +import android.util.Log; +import android.view.View; import android.view.ViewConfiguration; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.MainThreadExecutor; -import com.android.launcher3.Utilities; -import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.states.InternalStateHandler; -import com.android.launcher3.util.TraceHelper; +import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper; import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper; +import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.SysuiEventLogger; import com.android.quickstep.views.RecentsView; -import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; -import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; -import com.android.systemui.shared.recents.view.RecentsTransition; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.AssistDataReceiver; -import com.android.systemui.shared.system.BackgroundExecutor; -import com.android.systemui.shared.system.RecentsAnimationControllerCompat; -import com.android.systemui.shared.system.RecentsAnimationListener; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; - /** * Helper class to handle various atomic commands for switching between Overview. */ @TargetApi(Build.VERSION_CODES.P) public class OverviewCommandHelper extends InternalStateHandler { - private static final int RID_RESET_SWIPE_HANDLER = 0; - private static final int RID_CANCEL_CONTROLLER = 1; - private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2; - private static final long RECENTS_LAUNCH_DURATION = 200; private static final String TAG = "OverviewCommandHelper"; @@ -91,16 +69,7 @@ public class OverviewCommandHelper extends InternalStateHandler { public final Intent homeIntent; public final ComponentName launcher; - private final SparseArray mCurrentCommandFinishRunnables = new SparseArray<>(); - // Monotonically increasing command ids. - private int mCurrentCommandId = 0; - private long mLastToggleTime; - private WindowTransformSwipeHandler mWindowTransformSwipeHandler; - - private final Point mWindowSize = new Point(); - private final Rect mTaskTargetRect = new Rect(); - private final RectF mTempTaskTargetRect = new RectF(); public OverviewCommandHelper(Context context) { mContext = context; @@ -132,112 +101,6 @@ public class OverviewCommandHelper extends InternalStateHandler { initWhenReady(); } - @UiThread - private void addFinishCommand(int requestId, int id, Runnable action) { - if (requestId < mCurrentCommandId) { - action.run(); - } else { - mCurrentCommandFinishRunnables.put(id, action); - } - } - - @UiThread - private void clearFinishCommand(int requestId, int id) { - if (requestId == mCurrentCommandId) { - mCurrentCommandFinishRunnables.remove(id); - } - } - - @UiThread - private void initSwipeHandler(ActivityControlHelper helper, long time, - Consumer onAnimationInitCallback) { - final int commandId = mCurrentCommandId; - final RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); - final int runningTaskId = runningTask.id; - final WindowTransformSwipeHandler handler = - new WindowTransformSwipeHandler(runningTask, mContext, time, helper); - - // Preload the plan - mRecentsModel.loadTasks(runningTaskId, null); - mWindowTransformSwipeHandler = handler; - - mTempTaskTargetRect.setEmpty(); - handler.setGestureEndCallback(() -> { - if (mWindowTransformSwipeHandler == handler) { - mWindowTransformSwipeHandler = null; - mTempTaskTargetRect.setEmpty(); - } - clearFinishCommand(commandId, RID_RESET_SWIPE_HANDLER); - clearFinishCommand(commandId, RID_CANCEL_CONTROLLER); - }); - handler.initWhenReady(); - addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset); - - TraceHelper.beginSection(TAG); - Runnable startActivity = () -> helper.startRecentsFromButton(mContext, - addToIntent(homeIntent), - new RecentsAnimationListener() { - public void onAnimationStart( - RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, - Rect minimizedHomeBounds) { - if (mWindowTransformSwipeHandler == handler) { - TraceHelper.partitionSection(TAG, "Received"); - handler.onRecentsAnimationStart(controller, apps, homeContentInsets, - minimizedHomeBounds); - mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize)); - - ThumbnailData thumbnail = mAM.getTaskThumbnail(runningTaskId, - true /* reducedResolution */); - mMainThreadExecutor.execute(() -> { - addFinishCommand(commandId, - RID_CANCEL_CONTROLLER, () -> controller.finish(true)); - if (commandId == mCurrentCommandId) { - onAnimationInitCallback.accept(handler); - - // The animation has started, which means the other activity - // should be paused, lets update the thumbnail - handler.switchToScreenshotImmediate(thumbnail); - } - }); - } else { - TraceHelper.endSection(TAG, "Finishing no handler"); - controller.finish(false /* toHome */); - } - } - - public void onAnimationCanceled() { - TraceHelper.endSection(TAG, "Cancelled: " + handler); - if (mWindowTransformSwipeHandler == handler) { - handler.onRecentsAnimationCanceled(); - } - } - }); - - // We should almost always get touch-town on background thread. This is an edge case - // when the background Choreographer has not yet initialized. - BackgroundExecutor.get().submit(startActivity); - } - - @UiThread - private void startZoomOutAnim(final WindowTransformSwipeHandler handler) { - final int commandId = mCurrentCommandId; - ValueAnimator anim = ValueAnimator.ofInt(0, -handler.getTransitionLength()); - anim.addUpdateListener((a) -> handler.updateDisplacement((Integer) a.getAnimatedValue())); - anim.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - handler.onGestureEnded(0); - clearFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION); - } - }); - handler.onGestureStarted(); - anim.setDuration(RECENTS_LAUNCH_DURATION); - anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); - anim.start(); - addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel); - } - public void onOverviewToggle() { // If currently screen pinning, do not enter overview if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { @@ -245,45 +108,7 @@ public class OverviewCommandHelper extends InternalStateHandler { } ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps"); - long time = SystemClock.elapsedRealtime(); - mMainThreadExecutor.execute(() -> { - long elapsedTime = time - mLastToggleTime; - mLastToggleTime = time; - - mCurrentCommandId++; - mTempTaskTargetRect.round(mTaskTargetRect); - int runnableCount = mCurrentCommandFinishRunnables.size(); - if (runnableCount > 0) { - for (int i = 0; i < runnableCount; i++) { - mCurrentCommandFinishRunnables.valueAt(i).run(); - } - mCurrentCommandFinishRunnables.clear(); - } - - // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows - // the menu activity which takes window focus, prevening the right condition from - // being run below - ActivityControlHelper helper = getActivityControlHelper(); - RecentsView recents = helper.getVisibleRecentsView(); - if (recents != null) { - // Launch the next task - recents.showNextTask(); - } else { - if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { - // The user tried to launch back into overview too quickly, either after - // launching an app, or before overview has actually shown, just ignore for now - return; - } - - // Start overview - if (helper.switchToRecentsIfVisible()) { - SysuiEventLogger.writeDummyRecentsTransition(0); - // Do nothing - } else { - initSwipeHandler(helper, time, this::startZoomOutAnim); - } - } - }); + mMainThreadExecutor.execute(new RecentsActivityCommand<>()); } public void onOverviewShown() { @@ -298,48 +123,6 @@ public class OverviewCommandHelper extends InternalStateHandler { ); } - public void onOverviewHidden() { - getLauncher().runOnUiThread(() -> { - if (isOverviewAlmostVisible()) { - final RecentsView rv = getLauncher().getOverviewPanel(); - rv.launchNextTask(); - } - } - ); - } - - @WorkerThread - private void startLastTask() { - // TODO: This should go through recents model. - List tasks = mAM.getRecentTasks(2, UserHandle.myUserId()); - if (tasks.size() > 1) { - RecentTaskInfo rti = tasks.get(1); - - final ActivityOptions options; - if (!mTaskTargetRect.isEmpty()) { - final Rect targetRect = new Rect(mTaskTargetRect); - targetRect.offset(Utilities.isRtl(mContext.getResources()) - ? - mTaskTargetRect.width() : mTaskTargetRect.width(), 0); - final AppTransitionAnimationSpecCompat specCompat = - new AppTransitionAnimationSpecCompat(rti.id, null, targetRect); - AppTransitionAnimationSpecsFuture specFuture = - new AppTransitionAnimationSpecsFuture(mMainThreadExecutor.getHandler()) { - - @Override - public List composeSpecs() { - return Collections.singletonList(specCompat); - } - }; - options = RecentsTransition.createAspectScaleAnimation(mContext, - mMainThreadExecutor.getHandler(), true /* scaleUp */, - specFuture, () -> {}); - } else { - options = ActivityOptions.makeBasic(); - } - mAM.startActivityFromRecents(rti.id, options); - } - } - private boolean isOverviewAlmostVisible() { if (clearReference()) { return true; @@ -370,4 +153,123 @@ public class OverviewCommandHelper extends InternalStateHandler { return new LauncherActivityControllerHelper(); } } + + private class RecentsActivityCommand implements Runnable { + + private final ActivityControlHelper mHelper; + private final long mCreateTime; + private final int mRunningTaskId; + + private ActivityInitListener mListener; + private T mActivity; + + public RecentsActivityCommand() { + mHelper = getActivityControlHelper(); + mCreateTime = SystemClock.elapsedRealtime(); + mRunningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().id; + + // Preload the plan + mRecentsModel.loadTasks(mRunningTaskId, null); + } + + @Override + public void run() { + long elapsedTime = mCreateTime - mLastToggleTime; + mLastToggleTime = mCreateTime; + + // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows + // the menu activity which takes window focus, preventing the right condition from + // being run below + RecentsView recents = mHelper.getVisibleRecentsView(); + if (recents != null) { + // Launch the next task + recents.showNextTask(); + } else { + if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { + // The user tried to launch back into overview too quickly, either after + // launching an app, or before overview has actually shown, just ignore for now + return; + } + + // Start overview + if (mHelper.switchToRecentsIfVisible()) { + SysuiEventLogger.writeDummyRecentsTransition(0); + // Do nothing + } else { + mListener = mHelper.createActivityInitListener(this::onActivityReady); + mListener.registerAndStartActivity(homeIntent, this::createWindowAnimation, + mContext, mMainThreadExecutor.getHandler(), RECENTS_LAUNCH_DURATION); + } + } + } + + private boolean onActivityReady(T activity, Boolean wasVisible) { + activity.getOverviewPanel().setCurrentTask(mRunningTaskId); + AbstractFloatingView.closeAllOpenViews(activity, wasVisible); + mHelper.prepareRecentsUI(activity, wasVisible); + if (wasVisible) { + AnimatorPlaybackController controller = + mHelper.createControllerForVisibleActivity(activity); + controller.dispatchOnStart(); + ValueAnimator anim = + controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); + anim.setInterpolator(FAST_OUT_SLOW_IN); + anim.start(); + } + mActivity = activity; + return false; + } + + private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { + if (mListener != null) { + mListener.unregister(); + } + RemoteAnimationProvider.showOpeningTarget(targetCompats); + AnimatorSet anim = new AnimatorSet(); + if (mActivity == null) { + Log.e(TAG, "Animation created, before activity"); + anim.play(ValueAnimator.ofInt(0, 1).setDuration(100)); + return anim; + } + + RemoteAnimationTargetCompat closingTarget = null; + // Use the top closing app to determine the insets for the animation + for (RemoteAnimationTargetCompat target : targetCompats) { + if (target.mode == MODE_CLOSING) { + closingTarget = target; + break; + } + } + if (closingTarget == null) { + Log.e(TAG, "No closing app"); + anim.play(ValueAnimator.ofInt(0, 1).setDuration(100)); + return anim; + } + + final ClipAnimationHelper clipHelper = new ClipAnimationHelper(); + + // At this point, the activity is already started and laid-out. Get the home-bounds + // relative to the screen using the rootView of the activity. + int loc[] = new int[2]; + View rootView = mActivity.getRootView(); + rootView.getLocationOnScreen(loc); + Rect homeBounds = new Rect(loc[0], loc[1], + loc[0] + rootView.getWidth(), loc[1] + rootView.getHeight()); + clipHelper.updateSource(homeBounds, closingTarget); + + Rect targetRect = new Rect(); + mHelper.getSwipeUpDestinationAndLength( + mActivity.getDeviceProfile(), mActivity, targetRect); + clipHelper.updateTargetRect(targetRect); + + + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(RECENTS_LAUNCH_DURATION).setInterpolator(FAST_OUT_SLOW_IN); + valueAnimator.addUpdateListener((v) -> { + clipHelper.applyTransform(targetCompats, (float) v.getAnimatedValue()); + }); + anim.play(valueAnimator); + return anim; + } + } } diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java index 5bd606eb4a..77f0e7a53f 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java +++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java @@ -16,9 +16,14 @@ package com.android.quickstep; import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; import android.os.Build; +import android.os.Bundle; +import android.os.Handler; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.util.RemoteAnimationProvider; import java.lang.ref.WeakReference; import java.util.function.BiPredicate; @@ -78,4 +83,13 @@ public class RecentsActivityTracker implements ActivityInitListener { return sCurrentActivity.get(); } } + + @Override + public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, + Context context, Handler handler, long duration) { + register(); + + Bundle options = animProvider.toActivityOptions(handler, duration).toBundle(); + context.startActivity(intent, options); + } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java b/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java deleted file mode 100644 index a25e192dc2..0000000000 --- a/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2018 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 android.graphics.Rect; - -import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.system.RecentsAnimationControllerCompat; -import com.android.systemui.shared.system.RecentsAnimationListener; -import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.TransactionCompat; -import com.android.systemui.shared.system.WindowManagerWrapper; -import java.util.function.Consumer; - -/** - * Class to create activity options to emulate recents transition. - */ -public class RecentsAnimationActivityOptions implements RemoteAnimationRunnerCompat { - - private final RecentsAnimationListener mListener; - private final Runnable mFinishCallback; - - public RecentsAnimationActivityOptions(RecentsAnimationListener listener, - Runnable finishCallback) { - mListener = listener; - mFinishCallback = finishCallback; - } - - @Override - public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, - Runnable runnable) { - showOpeningTarget(targetCompats); - RemoteRecentsAnimationControllerCompat dummyRecentsAnim = - new RemoteRecentsAnimationControllerCompat(() -> { - runnable.run(); - if (mFinishCallback != null) { - mFinishCallback.run(); - } - }); - - Rect insets = new Rect(); - WindowManagerWrapper.getInstance().getStableInsets(insets); - mListener.onAnimationStart(dummyRecentsAnim, targetCompats, insets, null); - } - - @Override - public void onAnimationCancelled() { - mListener.onAnimationCanceled(); - } - - private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) { - TransactionCompat t = new TransactionCompat(); - for (RemoteAnimationTargetCompat target : targetCompats) { - int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING - ? Integer.MAX_VALUE - : target.prefixOrderIndex; - t.setLayer(target.leash, layer); - t.show(target.leash); - } - t.apply(); - } - - private class RemoteRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat { - - final Runnable mFinishCallback; - - public RemoteRecentsAnimationControllerCompat(Runnable finishCallback) { - mFinishCallback = finishCallback; - } - - @Override - public ThumbnailData screenshotTask(int taskId) { - return new ThumbnailData(); - } - - @Override - public void setInputConsumerEnabled(boolean enabled) { } - - @Override - public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { } - - @Override - public void finish(boolean toHome) { - // This should never be called with toHome == false - if (mFinishCallback != null) { - mFinishCallback.run(); - } - } - } -} diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index f6cf85a52d..1b3dd2eb40 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -30,11 +30,8 @@ import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Resources; -import android.graphics.Matrix; -import android.graphics.Matrix.ScaleToFit; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -64,11 +61,11 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.ActivityControlHelper.LayoutListener; import com.android.quickstep.TouchConsumer.InteractionType; +import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.util.SysuiEventLogger; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.recents.utilities.RectFEvaluator; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; @@ -132,26 +129,8 @@ public class WindowTransformSwipeHandler { private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f; - // The bounds of the source app in device coordinates - private final Rect mSourceStackBounds = new Rect(); - // The insets of the source app - private final Rect mSourceInsets = new Rect(); - // The source app bounds with the source insets applied, in the source app window coordinates - private final RectF mSourceRect = new RectF(); - // The bounds of the task view in launcher window coordinates - private final RectF mTargetRect = new RectF(); - // Doesn't change after initialized, used as an anchor when changing mTargetRect - private final RectF mInitialTargetRect = new RectF(); - // The insets to be used for clipping the app window, which can be larger than mSourceInsets - // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In - // app window coordinates. - private final RectF mSourceWindowClipInsets = new RectF(); + private final ClipAnimationHelper mClipAnimationHelper = new ClipAnimationHelper(); - // The bounds of launcher (not including insets) in device coordinates - private final Rect mHomeStackBounds = new Rect(); - // The clip rect in source app window coordinates - private final Rect mClipRect = new Rect(); - private final RectFEvaluator mRectFEvaluator = new RectFEvaluator(); protected Runnable mGestureEndCallback; protected boolean mIsGoingToHome; private DeviceProfile mDp; @@ -192,14 +171,9 @@ public class WindowTransformSwipeHandler { InputConsumerController.getRecentsAnimationInputConsumer(); private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); - private Matrix mTmpMatrix = new Matrix(); private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; - // Only used with the recents activity, when the screenshot should be fetched at the beginning - // of the animation and not at the end when the activity is already paused - private boolean mSkipScreenshotAtEndOfTransition; - WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, ActivityControlHelper controller) { mContext = context; @@ -273,42 +247,11 @@ public class WindowTransformSwipeHandler { private void initTransitionEndpoints(DeviceProfile dp) { mDp = dp; - mSourceRect.set(mSourceInsets.left, mSourceInsets.top, - mSourceStackBounds.width() - mSourceInsets.right, - mSourceStackBounds.height() - mSourceInsets.bottom); Rect tempRect = new Rect(); mTransitionDragLength = mActivityControlHelper .getSwipeUpDestinationAndLength(dp, mContext, tempRect); - - mTargetRect.set(tempRect); - mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left, - mHomeStackBounds.top - mSourceStackBounds.top); - mInitialTargetRect.set(mTargetRect); - - // Calculate the clip based on the target rect (since the content insets and the - // launcher insets may differ, so the aspect ratio of the target rect can differ - // from the source rect. The difference between the target rect (scaled to the - // source rect) is the amount to clip on each edge. - RectF scaledTargetRect = new RectF(mTargetRect); - Utilities.scaleRectFAboutCenter(scaledTargetRect, - mSourceRect.width() / mTargetRect.width()); - scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top); - mSourceWindowClipInsets.set( - Math.max(scaledTargetRect.left, 0), - Math.max(scaledTargetRect.top, 0), - Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0), - Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0)); - mSourceRect.set(scaledTargetRect); - } - - public int getTransitionLength() { - return mTransitionDragLength; - } - - public RectF getTargetRect(Point outWindowSize) { - outWindowSize.set(mDp.widthPx, mDp.heightPx); - return mInitialTargetRect; + mClipAnimationHelper.updateTargetRect(tempRect); } private long getFadeInDuration() { @@ -482,40 +425,10 @@ public class WindowTransformSwipeHandler { synchronized (mRecentsAnimationWrapper) { if (mRecentsAnimationWrapper.controller != null) { - RectF currentRect; - synchronized (mTargetRect) { - Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB - ? ACCEL_2 : LINEAR; - float interpolated = interpolator.getInterpolation(shift); - currentRect = mRectFEvaluator.evaluate(interpolated, mSourceRect, mTargetRect); - // Stay lined up with the center of the target, since it moves for quick scrub. - currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0); - } - - mClipRect.left = (int) (mSourceWindowClipInsets.left * shift); - mClipRect.top = (int) (mSourceWindowClipInsets.top * shift); - mClipRect.right = (int) - (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * shift)); - mClipRect.bottom = (int) - (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * shift)); - - mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); - - TransactionCompat transaction = new TransactionCompat(); - for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { - if (app.mode == MODE_CLOSING) { - mTmpMatrix.postTranslate(app.position.x, app.position.y); - transaction.setMatrix(app.leash, mTmpMatrix) - .setWindowCrop(app.leash, mClipRect); - - if (app.isNotInRecents) { - transaction.setAlpha(app.leash, 1 - shift); - } - - transaction.show(app.leash); - } - } - transaction.apply(); + Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB + ? ACCEL_2 : LINEAR; + float interpolated = interpolator.getInterpolation(shift); + mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targets, interpolated); } } @@ -533,13 +446,9 @@ public class WindowTransformSwipeHandler { if (firstTask != null) { int scrollForFirstTask = mRecentsView.getScrollForPage(0); int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX()); - synchronized (mTargetRect) { - mTargetRect.set(mInitialTargetRect); - Utilities.scaleRectFAboutCenter(mTargetRect, firstTask.getScaleX()); - float offsetX = offsetFromFirstTask + firstTask.getTranslationX(); - float offsetY = mRecentsView.getTranslationY(); - mTargetRect.offset(offsetX, offsetY); - } + mClipAnimationHelper.offsetTarget(firstTask.getScaleX(), + offsetFromFirstTask + firstTask.getTranslationX(), + mRecentsView.getTranslationY()); } if (mRecentsAnimationWrapper.controller != null) { // TODO: This logic is spartanic! @@ -564,13 +473,15 @@ public class WindowTransformSwipeHandler { for (RemoteAnimationTargetCompat target : apps) { if (target.mode == MODE_CLOSING) { DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext); + final Rect homeStackBounds; + if (minimizedHomeBounds != null) { - mHomeStackBounds.set(minimizedHomeBounds); + homeStackBounds = minimizedHomeBounds; dp = dp.getMultiWindowProfile(mContext, new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height())); dp.updateInsets(homeContentInsets); } else { - mHomeStackBounds.set(new Rect(0, 0, dp.widthPx, dp.heightPx)); + homeStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx); // TODO: Workaround for an existing issue where the home content insets are // not valid immediately after rotation, just use the stable insets for now Rect insets = new Rect(); @@ -578,16 +489,7 @@ public class WindowTransformSwipeHandler { dp.updateInsets(insets); } - // Initialize the start and end animation bounds - // TODO: Remove once platform is updated - try { - mSourceInsets.set(target.getContentInsets()); - } catch (Error e) { - // TODO: Remove once platform is updated, use stable insets as fallback - WindowManagerWrapper.getInstance().getStableInsets(mSourceInsets); - } - mSourceStackBounds.set(target.sourceContainerBounds); - + mClipAnimationHelper.updateSource(homeStackBounds, target); initTransitionEndpoints(dp); } } @@ -736,7 +638,7 @@ public class WindowTransformSwipeHandler { }; synchronized (mRecentsAnimationWrapper) { - if (mRecentsAnimationWrapper.controller != null && !mSkipScreenshotAtEndOfTransition) { + if (mRecentsAnimationWrapper.controller != null) { TransactionCompat transaction = new TransactionCompat(); for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { if (app.mode == MODE_CLOSING) { @@ -763,12 +665,6 @@ public class WindowTransformSwipeHandler { doLogGesture(true /* toLauncher */); } - @UiThread - public void switchToScreenshotImmediate(ThumbnailData thumbnail) { - mRecentsView.updateThumbnail(mRunningTaskId, thumbnail); - mSkipScreenshotAtEndOfTransition = true; - } - private void setupLauncherUiAfterSwipeUpAnimation() { if (mLauncherTransitionController != null) { mLauncherTransitionController.getAnimationPlayer().end(); diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java new file mode 100644 index 0000000000..0f895b851f --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; + +import android.graphics.Matrix; +import android.graphics.Matrix.ScaleToFit; +import android.graphics.Rect; +import android.graphics.RectF; + +import com.android.launcher3.Utilities; +import com.android.systemui.shared.recents.utilities.RectFEvaluator; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; + +/** + * Utility class to handle window clip animation + */ +public class ClipAnimationHelper { + + // The bounds of the source app in device coordinates + private final Rect mSourceStackBounds = new Rect(); + // The insets of the source app + private final Rect mSourceInsets = new Rect(); + // The source app bounds with the source insets applied, in the source app window coordinates + private final RectF mSourceRect = new RectF(); + // The bounds of the task view in launcher window coordinates + private final RectF mTargetRect = new RectF(); + // Doesn't change after initialized, used as an anchor when changing mTargetRect + private final RectF mInitialTargetRect = new RectF(); + // The insets to be used for clipping the app window, which can be larger than mSourceInsets + // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In + // app window coordinates. + private final RectF mSourceWindowClipInsets = new RectF(); + + // The bounds of launcher (not including insets) in device coordinates + public final Rect mHomeStackBounds = new Rect(); + + // The clip rect in source app window coordinates + private final Rect mClipRect = new Rect(); + private final RectFEvaluator mRectFEvaluator = new RectFEvaluator(); + private final Matrix mTmpMatrix = new Matrix(); + + + public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) { + mHomeStackBounds.set(homeStackBounds); + mSourceInsets.set(target.getContentInsets()); + mSourceStackBounds.set(target.sourceContainerBounds); + + // TODO: Should sourceContainerBounds already have this offset? + mSourceStackBounds.offsetTo(target.position.x, target.position.y); + } + + public void updateTargetRect(Rect targetRect) { + mSourceRect.set(mSourceInsets.left, mSourceInsets.top, + mSourceStackBounds.width() - mSourceInsets.right, + mSourceStackBounds.height() - mSourceInsets.bottom); + mTargetRect.set(targetRect); + mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left, + mHomeStackBounds.top - mSourceStackBounds.top); + + mInitialTargetRect.set(mTargetRect); + + // Calculate the clip based on the target rect (since the content insets and the + // launcher insets may differ, so the aspect ratio of the target rect can differ + // from the source rect. The difference between the target rect (scaled to the + // source rect) is the amount to clip on each edge. + RectF scaledTargetRect = new RectF(mTargetRect); + Utilities.scaleRectFAboutCenter(scaledTargetRect, + mSourceRect.width() / mTargetRect.width()); + scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top); + mSourceWindowClipInsets.set( + Math.max(scaledTargetRect.left, 0), + Math.max(scaledTargetRect.top, 0), + Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0), + Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0)); + mSourceRect.set(scaledTargetRect); + } + + public void applyTransform(RemoteAnimationTargetCompat[] targets, float progress) { + RectF currentRect; + synchronized (mTargetRect) { + currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); + // Stay lined up with the center of the target, since it moves for quick scrub. + currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0); + } + + mClipRect.left = (int) (mSourceWindowClipInsets.left * progress); + mClipRect.top = (int) (mSourceWindowClipInsets.top * progress); + mClipRect.right = (int) + (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress)); + mClipRect.bottom = (int) + (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress)); + + mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); + + TransactionCompat transaction = new TransactionCompat(); + for (RemoteAnimationTargetCompat app : targets) { + if (app.mode == MODE_CLOSING) { + mTmpMatrix.postTranslate(app.position.x, app.position.y); + transaction.setMatrix(app.leash, mTmpMatrix) + .setWindowCrop(app.leash, mClipRect); + if (app.isNotInRecents) { + transaction.setAlpha(app.leash, 1 - progress); + } + + transaction.show(app.leash); + } + } + transaction.apply(); + } + + public void offsetTarget(float scale, float offsetX, float offsetY) { + synchronized (mTargetRect) { + mTargetRect.set(mInitialTargetRect); + Utilities.scaleRectFAboutCenter(mTargetRect, scale); + mTargetRect.offset(offsetX, offsetY); + } + } +} diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java new file mode 100644 index 0000000000..2ffcae38ef --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import android.animation.AnimatorSet; +import android.app.ActivityOptions; +import android.os.Handler; + +import com.android.launcher3.LauncherAnimationRunner; +import com.android.systemui.shared.system.ActivityOptionsCompat; +import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; + +@FunctionalInterface +public interface RemoteAnimationProvider { + + AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targets); + + default ActivityOptions toActivityOptions(Handler handler, long duration) { + LauncherAnimationRunner runner = new LauncherAnimationRunner(handler) { + @Override + public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { + return createWindowAnimation(targetCompats); + } + }; + return ActivityOptionsCompat.makeRemoteAnimation( + new RemoteAnimationAdapterCompat(runner, duration, 0)); + } + + static void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) { + TransactionCompat t = new TransactionCompat(); + for (RemoteAnimationTargetCompat target : targetCompats) { + int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING + ? Integer.MAX_VALUE + : target.prefixOrderIndex; + t.setLayer(target.leash, layer); + t.show(target.leash); + } + t.apply(); + } +} diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java index 6b7143d048..ac34d90b1d 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java +++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.views; +import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK; import static com.android.launcher3.states.RotationHelper.REQUEST_NONE; import android.graphics.Rect; @@ -39,6 +40,10 @@ public class LauncherLayoutListener extends AbstractFloatingView super(launcher, null); mLauncher = launcher; setVisibility(INVISIBLE); + + // For the duration of the gesture, lock the screen orientation to ensure that we do not + // rotate mid-quickscrub + launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK); } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index d95619c055..c2e1ce688e 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -130,13 +130,7 @@ public abstract class RecentsView private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { @Override public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { - for (int i = 0; i < getChildCount(); i++) { - final TaskView taskView = (TaskView) getChildAt(i); - if (taskView.getTask().key.id == taskId) { - taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot); - return; - } - } + updateThumbnail(taskId, snapshot); } @Override @@ -601,12 +595,7 @@ public abstract class RecentsView new ActivityManager.TaskDescription(), 0, new ComponentName("", ""), false); taskView.bind(mTmpRunningTask); } - - mRunningTaskId = runningTaskId; - setCurrentPage(0); - - // Load the tasks (if the loading is already - mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); + setCurrentTask(mRunningTaskId); // Hide the task that we are animating into, ignore if there is no associated task (ie. the // assistant) @@ -615,6 +604,17 @@ public abstract class RecentsView } } + /** + * Similar to {@link #showTask(int)} but does not put any restrictions on the first tile. + */ + public void setCurrentTask(int runningTaskId) { + mRunningTaskId = runningTaskId; + setCurrentPage(0); + + // Load the tasks (if the loading is already + mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); + } + public void showNextTask() { TaskView runningTaskView = getTaskView(mRunningTaskId); if (runningTaskView == null) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b410f4f798..90c55c983a 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -294,6 +294,7 @@ public class Launcher extends BaseDraggingActivity mPopupDataProvider = new PopupDataProvider(this); mRotationHelper = new RotationHelper(this); + mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent()); if (internalStateHandled) { @@ -341,8 +342,6 @@ public class Launcher extends BaseDraggingActivity getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); - mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); - if (mLauncherCallbacks != null) { mLauncherCallbacks.onCreate(savedInstanceState); } From 73387743d7390baf86664f9dde9aa906ffbe404f Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 5 Apr 2018 13:57:07 -0700 Subject: [PATCH 69/81] Make drag handle visible in overview landscape mode. Bug: 77552542 Change-Id: Ia05662f83dc865b7a1a134e225373a804d26fc3e --- .../src/com/android/launcher3/uioverrides/OverviewState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index d97b7b2643..ec547326e9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -110,7 +110,7 @@ public class OverviewState extends LauncherState { @Override public int getVisibleElements(Launcher launcher) { if (launcher.getDeviceProfile().isVerticalBarLayout()) { - return NONE; + return DRAG_HANDLE_INDICATOR; } else { return HOTSEAT_SEARCH_BOX | DRAG_HANDLE_INDICATOR | (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent() From 0fd7c6c9da9194aba8a940fc5d56fd4c230c1079 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 5 Apr 2018 14:52:32 -0700 Subject: [PATCH 70/81] Fix bug where BTV text alpha stays 0 when PopupContainer closed w/o animation. Bug: 77565147 Change-Id: I71501c7a65369386efcb7b1a36f19b117e119ed9 --- .../android/launcher3/popup/PopupContainerWithArrow.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 422a4ecd26..ba94b2fe25 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -516,6 +516,12 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, mOriginalIcon.forceHideBadge(false); } + @Override + protected void closeComplete() { + super.closeComplete(); + mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); + } + @Override public boolean onTouch(View v, MotionEvent ev) { // Touched a shortcut, update where it was touched so we can drag from there on long click. From 0164d7d346ba1bee54504529ae787508fdc260e2 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 5 Apr 2018 16:00:09 -0700 Subject: [PATCH 71/81] Add null check for empty recents view Bug: 77533523 Change-Id: I8ba58d3ed35212b6c06e689281cb25b55ac79ae2 --- quickstep/src/com/android/quickstep/views/RecentsView.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index d95619c055..b2bf030b74 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1064,7 +1064,10 @@ public abstract class RecentsView @Override protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); - getChildAt(mCurrentPage).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); + View currChild = getChildAt(mCurrentPage); + if (currChild != null) { + currChild.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); + } } @Override From a0c9d90e7023f243ea93be99b7a5feb935008ea1 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 5 Apr 2018 17:05:29 -0700 Subject: [PATCH 72/81] Fixing taskView sometimes visible during swipe-up transition Caused by change-id: I4defce3a9745407523de651aeb28a37867567507 Change-Id: I670e20da6086d257b4de45d4e1310ef6b4314c46 --- .../src/com/android/quickstep/WindowTransformSwipeHandler.java | 1 + quickstep/src/com/android/quickstep/views/RecentsView.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 1b3dd2eb40..d4c35e0b1e 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -647,6 +647,7 @@ public class WindowTransformSwipeHandler { mRecentsAnimationWrapper.controller.screenshotTask(app.taskId); TaskView taskView = mRecentsView.updateThumbnail(app.taskId, thumbnail); if (taskView != null) { + taskView.setAlpha(1); // Defer finishing the animation until the next launcher frame with the // new thumbnail mActivityControlHelper.executeOnNextDraw(mActivity, taskView, diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index c2e1ce688e..751ad2a323 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -232,7 +232,6 @@ public abstract class RecentsView final TaskView taskView = (TaskView) getChildAt(i); if (taskView.getTask().key.id == taskId) { taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData); - taskView.setAlpha(1); return taskView; } } From f3c10bf15f18d20657e980ba801268238aea8298 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 5 Apr 2018 18:05:23 -0700 Subject: [PATCH 73/81] Ignore touch events on task view when menu is open For example, long pressing icon and then dragging in the same motion should be ignored Bug: 77652647 Change-Id: I9cc53c2873950f216d51d90f749b3cc0d0744d3c --- quickstep/src/com/android/quickstep/views/TaskView.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 42da472b5c..1aa2d98f5c 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -138,7 +138,10 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback mSnapshotView.setThumbnail(task, thumbnailData); mIconView.setImageDrawable(task.icon); mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this)); - mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this)); + mIconView.setOnLongClickListener(icon -> { + requestDisallowInterceptTouchEvent(true); + return TaskMenuView.showForTask(this); + }); } @Override From d39148afb0f9a95b61b444fb02a0f826be93c8d0 Mon Sep 17 00:00:00 2001 From: Mario Bertschler Date: Thu, 5 Apr 2018 22:44:42 +0200 Subject: [PATCH 74/81] Adding FLAG_ICON_BADGED and check flag in DragView.getBadge. Bug: 77634973 Change-Id: I0e398bea7aa86246616e37bbd76f0936facb83ba --- src/com/android/launcher3/ItemInfoWithIcon.java | 5 +++++ src/com/android/launcher3/dragndrop/DragView.java | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java index bf985c38da..4677d31819 100644 --- a/src/com/android/launcher3/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/ItemInfoWithIcon.java @@ -90,6 +90,11 @@ public abstract class ItemInfoWithIcon extends ItemInfo { */ public static final int FLAG_ADAPTIVE_ICON = 1 << 8; + /** + * Flag indicating that the icon is badged. + */ + public static final int FLAG_ICON_BADGED = 1 << 9; + /** * Status associated with the system state of the underlying item. This is calculated every * time a new info is created and not persisted on the disk. diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index 8d4f2ef0a3..e1e1f83a7c 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -46,6 +46,7 @@ import android.view.View; import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.ItemInfo; +import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherAppState; @@ -69,6 +70,8 @@ import com.android.launcher3.widget.PendingAddShortcutInfo; import java.util.Arrays; import java.util.List; +import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED; + public class DragView extends View { private static final ColorMatrix sTempMatrix1 = new ColorMatrix(); private static final ColorMatrix sTempMatrix2 = new ColorMatrix(); @@ -364,7 +367,10 @@ public class DragView extends View { private Drawable getBadge(ItemInfo info, LauncherAppState appState, Object obj) { int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize; if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - if (info.id == ItemInfo.NO_ID || !(obj instanceof ShortcutInfoCompat)) { + boolean iconBadged = (info instanceof ItemInfoWithIcon) + && (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0; + if ((info.id == ItemInfo.NO_ID && !iconBadged) + || !(obj instanceof ShortcutInfoCompat)) { // The item is not yet added on home screen. return new FixedSizeEmptyDrawable(iconSize); } From 0635de29a968949a36044f72e763178a6aa07b8d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 6 Apr 2018 08:43:19 -0700 Subject: [PATCH 75/81] Removing Launcher assumption from OverviewCommand, so that it works with fallback activity Bug: 75979063 Change-Id: I3a851f6ce4725cee590eac9004eff1180f3780bb --- .../quickstep/OverviewCommandHelper.java | 99 +++++++------------ .../android/quickstep/views/RecentsView.java | 5 - 2 files changed, 38 insertions(+), 66 deletions(-) diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 2fb4127258..d76c49a09f 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -15,7 +15,6 @@ */ package com.android.quickstep; -import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; @@ -35,11 +34,8 @@ import android.view.ViewConfiguration; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.states.InternalStateHandler; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper; import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper; @@ -54,7 +50,7 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; * Helper class to handle various atomic commands for switching between Overview. */ @TargetApi(Build.VERSION_CODES.P) -public class OverviewCommandHelper extends InternalStateHandler { +public class OverviewCommandHelper { private static final long RECENTS_LAUNCH_DURATION = 200; @@ -95,55 +91,18 @@ public class OverviewCommandHelper extends InternalStateHandler { homeIntent.setComponent(launcher).setPackage(null); } - private void openRecents() { - Intent intent = addToIntent(new Intent(homeIntent)); - mContext.startActivity(intent); - initWhenReady(); - } - public void onOverviewToggle() { // If currently screen pinning, do not enter overview - if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { + if (mAM.isScreenPinningActive()) { return; } - ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps"); + mAM.closeSystemWindows("recentapps"); mMainThreadExecutor.execute(new RecentsActivityCommand<>()); } public void onOverviewShown() { - getLauncher().runOnUiThread(() -> { - if (isOverviewAlmostVisible()) { - final RecentsView rv = getLauncher().getOverviewPanel(); - rv.snapToTaskAfterNext(); - } else { - openRecents(); - } - } - ); - } - - private boolean isOverviewAlmostVisible() { - if (clearReference()) { - return true; - } - if (!mAM.getRunningTask().topActivity.equals(launcher)) { - return false; - } - Launcher launcher = getLauncher(); - return launcher != null && launcher.isStarted() && launcher.isInState(OVERVIEW); - } - - private Launcher getLauncher() { - return (Launcher) LauncherAppState.getInstance(mContext).getModel().getCallback(); - } - - @Override - protected boolean init(Launcher launcher, boolean alreadyOnHome) { - AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome); - launcher.getStateManager().goToState(OVERVIEW, alreadyOnHome); - clearReference(); - return false; + mMainThreadExecutor.execute(new ShowRecentsCommand()); } public ActivityControlHelper getActivityControlHelper() { @@ -154,9 +113,23 @@ public class OverviewCommandHelper extends InternalStateHandler { } } + private class ShowRecentsCommand extends RecentsActivityCommand { + + @Override + protected boolean handleCommand(long elapsedTime) { + RecentsView recents = mHelper.getVisibleRecentsView(); + if (recents != null) { + recents.snapToTaskAfterNext(); + return true; + } else { + return false; + } + } + } + private class RecentsActivityCommand implements Runnable { - private final ActivityControlHelper mHelper; + protected final ActivityControlHelper mHelper; private final long mCreateTime; private final int mRunningTaskId; @@ -166,7 +139,7 @@ public class OverviewCommandHelper extends InternalStateHandler { public RecentsActivityCommand() { mHelper = getActivityControlHelper(); mCreateTime = SystemClock.elapsedRealtime(); - mRunningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().id; + mRunningTaskId = mAM.getRunningTask().id; // Preload the plan mRecentsModel.loadTasks(mRunningTaskId, null); @@ -177,20 +150,7 @@ public class OverviewCommandHelper extends InternalStateHandler { long elapsedTime = mCreateTime - mLastToggleTime; mLastToggleTime = mCreateTime; - // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows - // the menu activity which takes window focus, preventing the right condition from - // being run below - RecentsView recents = mHelper.getVisibleRecentsView(); - if (recents != null) { - // Launch the next task - recents.showNextTask(); - } else { - if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { - // The user tried to launch back into overview too quickly, either after - // launching an app, or before overview has actually shown, just ignore for now - return; - } - + if (!handleCommand(elapsedTime)) { // Start overview if (mHelper.switchToRecentsIfVisible()) { SysuiEventLogger.writeDummyRecentsTransition(0); @@ -203,6 +163,23 @@ public class OverviewCommandHelper extends InternalStateHandler { } } + protected boolean handleCommand(long elapsedTime) { + // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows + // the menu activity which takes window focus, preventing the right condition from + // being run below + RecentsView recents = mHelper.getVisibleRecentsView(); + if (recents != null) { + // Launch the next task + recents.showNextTask(); + return true; + } else if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { + // The user tried to launch back into overview too quickly, either after + // launching an app, or before overview has actually shown, just ignore for now + return true; + } + return false; + } + private boolean onActivityReady(T activity, Boolean wasVisible) { activity.getOverviewPanel().setCurrentTask(mRunningTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 83fb634609..5a442d96b5 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -831,11 +831,6 @@ public abstract class RecentsView snapToPageRelative(1); } - public void launchNextTask() { - final TaskView nextTask = (TaskView) getChildAt(getNextPage()); - nextTask.launchTask(true); - } - public void setContentAlpha(float alpha) { if (mContentAlpha == alpha) { return; From d792a7723430cfc84d60af7d885bd51d2159df32 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 5 Apr 2018 13:37:46 -0700 Subject: [PATCH 76/81] Updating the card size logic In full screen always follow the device aspect ratio In multi-window, follow the 1:1 split window size Rotate the screen shot only in full-screen mode Bug: 70289009 Change-Id: Id5095565634d4d7920fefa929b28276db80bda5f --- quickstep/res/values/dimens.xml | 10 +- .../launcher3/uioverrides/OverviewState.java | 26 +---- .../quickstep/ActivityControlHelper.java | 5 +- .../fallback/FallbackRecentsView.java | 37 +++--- .../android/quickstep/util/LayoutUtils.java | 84 ++++++++++++++ .../quickstep/views/LauncherRecentsView.java | 30 +++-- .../android/quickstep/views/RecentsView.java | 81 +++----------- .../quickstep/views/TaskThumbnailView.java | 105 ++++++++---------- src/com/android/launcher3/DeviceProfile.java | 2 +- 9 files changed, 189 insertions(+), 191 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/LayoutUtils.java diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index ab6d8af7a4..c741913953 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -20,7 +20,6 @@ 48dp 12dp 2dp - 20dp 10dp + 40dp + 136dp + 200dp + 100dp + + 10dp diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index ec547326e9..9c7db3093a 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -19,13 +19,11 @@ import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE; -import android.graphics.Rect; import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.Workspace; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.views.RecentsView; @@ -47,14 +45,8 @@ public class OverviewState extends LauncherState { @Override public float[] getWorkspaceScaleAndTranslation(Launcher launcher) { - Rect pageRect = new Rect(); - RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect); - - if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) { - return super.getWorkspaceScaleAndTranslation(launcher); - } - - return getScaleAndTranslationForPageRect(launcher, pageRect); + // TODO: provide a valid value + return new float[]{1, 0, -launcher.getDeviceProfile().hotseatBarSizePx / 2}; } @Override @@ -93,20 +85,6 @@ public class OverviewState extends LauncherState { }; } - public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) { - Workspace ws = launcher.getWorkspace(); - float childWidth = ws.getNormalChildWidth(); - - float scale = pageRect.width() / childWidth; - Rect insets = launcher.getDragLayer().getInsets(); - - float halfHeight = ws.getExpectedHeight() / 2; - float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top); - float translationY = pageRect.top - childTop; - - return new float[] {scale, 0, translationY}; - } - @Override public int getVisibleElements(Launcher launcher) { if (launcher.getDeviceProfile().isVerticalBarLayout()) { diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index d82b8f437c..708bec06cb 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -44,6 +44,7 @@ import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.views.LauncherLayoutListener; +import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -122,7 +123,7 @@ public interface ActivityControlHelper { @Override public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) { - RecentsView.getPageRect(dp, context, outRect); + LauncherRecentsView.getPageRect(dp, context, outRect); if (dp.isVerticalBarLayout()) { Rect targetInsets = dp.getInsets(); int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right; @@ -271,7 +272,7 @@ public interface ActivityControlHelper { @Override public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) { - FallbackRecentsView.getCenterPageRect(dp, context, outRect); + FallbackRecentsView.getPageRect(dp, context, outRect); if (dp.isVerticalBarLayout()) { Rect targetInsets = dp.getInsets(); int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right; diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index 7d7f88fdb2..4ed165699e 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -18,15 +18,16 @@ package com.android.quickstep.fallback; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; +import android.support.annotation.AnyThread; import android.util.AttributeSet; import android.view.View; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Insettable; import com.android.quickstep.RecentsActivity; +import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; -public class FallbackRecentsView extends RecentsView implements Insettable { +public class FallbackRecentsView extends RecentsView { public FallbackRecentsView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -55,31 +56,19 @@ public class FallbackRecentsView extends RecentsView implements updateEmptyMessage(); } - @Override - public void setInsets(Rect insets) { - mInsets.set(insets); - DeviceProfile dp = mActivity.getDeviceProfile(); - Rect padding = getPadding(dp, getContext()); - verticalCenter(padding, dp); - setPadding(padding.left, padding.top, padding.right, padding.bottom); - } - - private static void verticalCenter(Rect padding, DeviceProfile dp) { - Rect insets = dp.getInsets(); - int totalSpace = (padding.top + padding.bottom - insets.top - insets.bottom) / 2; - padding.top = insets.top + totalSpace; - padding.bottom = insets.bottom + totalSpace; - } - - public static void getCenterPageRect(DeviceProfile grid, Context context, Rect outRect) { - Rect targetPadding = getPadding(grid, context); - verticalCenter(targetPadding, grid); - getPageRect(grid, context, outRect, targetPadding); - } - @Override public void draw(Canvas canvas) { maybeDrawEmptyMessage(canvas); super.draw(canvas); } + + @Override + protected void getTaskSize(DeviceProfile dp, Rect outRect) { + LayoutUtils.calculateTaskSize(getContext(), dp, 0, outRect); + } + + @AnyThread + public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) { + LayoutUtils.calculateTaskSize(context, grid, 0, outRect); + } } diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java new file mode 100644 index 0000000000..f29f9e4e92 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.RectF; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; + +public class LayoutUtils { + + public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) { + float extraSpace = dp.isVerticalBarLayout() ? 0 : dp.hotseatBarSizePx; + calculateTaskSize(context, dp, extraSpace, outRect); + } + + public static void calculateTaskSize(Context context, DeviceProfile dp, + float extraVerticalSpace, Rect outRect) { + float taskWidth, taskHeight, paddingHorz; + Resources res = context.getResources(); + Rect insets = dp.getInsets(); + + if (dp.isMultiWindowMode) { + DeviceProfile fullDp = dp.getFullScreenProfile(); + // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to + // account for system insets + taskWidth = fullDp.availableWidthPx; + taskHeight = fullDp.availableHeightPx; + float halfDividerSize = res.getDimension(R.dimen.multi_window_task_divider_size) / 2; + + if (fullDp.isLandscape) { + taskWidth = taskWidth / 2 - halfDividerSize; + } else { + taskHeight = taskHeight / 2 - halfDividerSize; + } + paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space); + } else { + taskWidth = dp.availableWidthPx; + taskHeight = dp.availableHeightPx; + paddingHorz = res.getDimension(dp.isVerticalBarLayout() + ? R.dimen.landscape_task_card_horz_space + : R.dimen.portrait_task_card_horz_space); + } + + float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin); + float paddingVert = res.getDimension(R.dimen.task_card_vert_space); + + // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless + // we override the insets ourselves. + int launcherVisibleWidth = dp.widthPx - insets.left - insets.right; + int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom; + + float availableHeight = launcherVisibleHeight + - topIconMargin - extraVerticalSpace - paddingVert; + float availableWidth = launcherVisibleWidth - paddingHorz; + + float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight); + float outWidth = scale * taskWidth; + float outHeight = scale * taskHeight; + + // Center in the visible space + float x = insets.left + (taskWidth - outWidth) / 2; + float y = insets.top + Math.max(topIconMargin, + (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2); + outRect.set(Math.round(x), Math.round(y), + Math.round(x + outWidth), Math.round(y + outHeight)); + } +} diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 6788827445..4b4af3fa7e 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -27,22 +27,22 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Build; +import android.support.annotation.AnyThread; import android.util.AttributeSet; import android.util.FloatProperty; import android.view.View; import android.view.ViewDebug; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.R; +import com.android.quickstep.util.LayoutUtils; /** * {@link RecentsView} used in Launcher activity */ @TargetApi(Build.VERSION_CODES.O) -public class LauncherRecentsView extends RecentsView implements Insettable { +public class LauncherRecentsView extends RecentsView { public static final FloatProperty TRANSLATION_Y_FACTOR = new FloatProperty("translationYFactor") { @@ -61,8 +61,6 @@ public class LauncherRecentsView extends RecentsView implements Insett @ViewDebug.ExportedProperty(category = "launcher") private float mTranslationYFactor; - private Rect mPagePadding = new Rect(); - public LauncherRecentsView(Context context) { this(context, null); } @@ -76,16 +74,6 @@ public class LauncherRecentsView extends RecentsView implements Insett setContentAlpha(0); } - @Override - public void setInsets(Rect insets) { - mInsets.set(insets); - DeviceProfile dp = mActivity.getDeviceProfile(); - Rect padding = getPadding(dp, getContext()); - setPadding(padding.left, padding.top, padding.right, padding.bottom); - mPagePadding.set(padding); - mPagePadding.top += getResources().getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); - } - @Override protected void onAllTasksRemoved() { mActivity.getStateManager().goToState(NORMAL); @@ -99,7 +87,7 @@ public class LauncherRecentsView extends RecentsView implements Insett public void setTranslationYFactor(float translationFactor) { mTranslationYFactor = translationFactor; - setTranslationY(mTranslationYFactor * (mPagePadding.bottom - mPagePadding.top)); + setTranslationY(mTranslationYFactor * (getPaddingBottom() - getPaddingTop())); } @Override @@ -138,4 +126,14 @@ public class LauncherRecentsView extends RecentsView implements Insett mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen)); return anim; } + + @Override + protected void getTaskSize(DeviceProfile dp, Rect outRect) { + LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); + } + + @AnyThread + public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) { + LayoutUtils.calculateLauncherTaskSize(context, grid, outRect); + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 83fb634609..c19f5dddb8 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -53,6 +53,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Insettable; import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -72,7 +73,6 @@ import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; -import com.android.systemui.shared.system.WindowManagerWrapper; import java.util.ArrayList; @@ -81,7 +81,9 @@ import java.util.ArrayList; */ @TargetApi(Build.VERSION_CODES.P) public abstract class RecentsView - extends PagedView implements OnSharedPreferenceChangeListener { + extends PagedView implements OnSharedPreferenceChangeListener, Insettable { + + private final Rect mTempRect = new Rect(); public static final FloatProperty CONTENT_ALPHA = new FloatProperty("contentAlpha") { @@ -96,8 +98,6 @@ public abstract class RecentsView } }; - - public static final FloatProperty ADJACENT_SCALE = new FloatProperty("adjacentScale") { @Override @@ -113,8 +113,6 @@ public abstract class RecentsView private static final String PREF_FLIP_RECENTS = "pref_flip_recents"; private static final int DISMISS_TASK_DURATION = 300; - private static final Rect sTempStableInsets = new Rect(); - protected final T mActivity; private final QuickScrubController mQuickScrubController; private final float mFastFlingVelocity; @@ -394,69 +392,20 @@ public abstract class RecentsView } } - protected static Rect getPadding(DeviceProfile profile, Context context) { - WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets); - Rect padding = new Rect(profile.workspacePadding); - - float taskWidth = profile.widthPx - sTempStableInsets.left - sTempStableInsets.right; - float taskHeight = profile.heightPx - sTempStableInsets.top - sTempStableInsets.bottom; - - float overviewHeight, overviewWidth; - if (profile.isVerticalBarLayout()) { - float maxPadding = Math.max(padding.left, padding.right); - - // Use the same padding on both sides for symmetry. - float availableWidth = taskWidth - 2 * maxPadding; - float availableHeight = profile.availableHeightPx - padding.top - padding.bottom - - sTempStableInsets.top; - float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight); - overviewHeight = taskHeight * scaledRatio; - overviewWidth = taskWidth * scaledRatio; - - } else { - overviewHeight = profile.availableHeightPx - padding.top - padding.bottom - - sTempStableInsets.top; - overviewWidth = taskWidth * overviewHeight / taskHeight; - } - - padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top - - Math.round(overviewHeight); - padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2); - - // If the height ratio is larger than the width ratio, the screenshot will get cropped - // at the bottom when swiping up. In this case, increase the top/bottom padding to make it - // the same aspect ratio. - Rect pageRect = new Rect(); - getPageRect(profile, context, pageRect, padding); - float widthRatio = (float) pageRect.width() / taskWidth; - float heightRatio = (float) pageRect.height() / taskHeight; - if (heightRatio > widthRatio) { - float additionalVerticalPadding = pageRect.height() - widthRatio * taskHeight; - additionalVerticalPadding = Math.round(additionalVerticalPadding); - padding.top += additionalVerticalPadding / 2; - padding.bottom += additionalVerticalPadding / 2; - } - - return padding; - } - - public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) { - Rect targetPadding = getPadding(grid, context); - getPageRect(grid, context, outRect, targetPadding); - } - - protected static void getPageRect(DeviceProfile grid, Context context, Rect outRect, - Rect targetPadding) { - Rect insets = grid.getInsets(); - outRect.set( - targetPadding.left + insets.left, - targetPadding.top + insets.top, - grid.widthPx - targetPadding.right - insets.right, - grid.heightPx - targetPadding.bottom - insets.bottom); - outRect.top += context.getResources() + @Override + public void setInsets(Rect insets) { + mInsets.set(insets); + DeviceProfile dp = mActivity.getDeviceProfile(); + getTaskSize(dp, mTempRect); + mTempRect.top -= getResources() .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); + setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top, + dp.widthPx - mTempRect.right - mInsets.right, + dp.heightPx - mTempRect.bottom - mInsets.bottom); } + protected abstract void getTaskSize(DeviceProfile dp, Rect outRect); + @Override protected boolean computeScrollHelper() { boolean scrolling = super.computeScrollHelper(); diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 8b41b58f38..58b7db7b22 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -22,12 +22,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ComposeShader; import android.graphics.LightingColorFilter; -import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; -import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; @@ -50,14 +47,16 @@ public class TaskThumbnailView extends View { private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256]; private final float mCornerRadius; - private final float mFadeLength; + private final BaseActivity mActivity; private final TaskOverlay mOverlay; private final Paint mPaint = new Paint(); - private final Paint mLockedPaint = new Paint(); + private final Paint mBackgroundPaint = new Paint(); private final Matrix mMatrix = new Matrix(); + private float mClipBottom = -1; + private Task mTask; private ThumbnailData mThumbnailData; protected BitmapShader mBitmapShader; @@ -75,10 +74,10 @@ public class TaskThumbnailView extends View { public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius); - mFadeLength = getResources().getDimension(R.dimen.task_fade_length); mOverlay = TaskOverlayFactory.get(context).createOverlay(this); mPaint.setFilterBitmap(true); - mLockedPaint.setColor(Color.WHITE); + mBackgroundPaint.setColor(Color.WHITE); + mActivity = BaseActivity.fromContext(context); } public void bind() { @@ -90,7 +89,9 @@ public class TaskThumbnailView extends View { */ public void setThumbnail(Task task, ThumbnailData thumbnailData) { mTask = task; - mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000); + int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000; + mPaint.setColor(color); + mBackgroundPaint.setColor(color); if (thumbnailData != null && thumbnailData.thumbnail != null) { Bitmap bm = thumbnailData.thumbnail; @@ -128,8 +129,23 @@ public class TaskThumbnailView extends View { if (mTask == null) { return; } - canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius, - mCornerRadius, mTask.isLocked ? mLockedPaint : mPaint); + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + if (mClipBottom > 0 && !mTask.isLocked) { + canvas.save(); + canvas.clipRect(0, 0, width, mClipBottom); + + canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, mPaint); + canvas.restore(); + canvas.save(); + canvas.clipRect(0, mClipBottom, width, height); + canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, + mBackgroundPaint); + canvas.restore(); + } else { + canvas.drawRoundRect(0, 0, width, height, mCornerRadius, + mCornerRadius, mTask.isLocked ? mBackgroundPaint : mPaint); + } } private void updateThumbnailPaintFilter() { @@ -137,7 +153,7 @@ public class TaskThumbnailView extends View { if (mBitmapShader != null) { LightingColorFilter filter = getLightingColorFilter(mul); mPaint.setColorFilter(filter); - mLockedPaint.setColorFilter(filter); + mBackgroundPaint.setColorFilter(filter); } else { mPaint.setColorFilter(null); mPaint.setColor(Color.argb(255, mul, mul, mul)); @@ -147,47 +163,38 @@ public class TaskThumbnailView extends View { private void updateThumbnailMatrix() { boolean rotate = false; + mClipBottom = -1; if (mBitmapShader != null && mThumbnailData != null) { float scale = mThumbnailData.scale; + Rect thumbnailInsets = mThumbnailData.insets; float thumbnailWidth = mThumbnailData.thumbnail.getWidth() - - (mThumbnailData.insets.left + mThumbnailData.insets.right) * scale; + (thumbnailInsets.left + thumbnailInsets.right) * scale; float thumbnailHeight = mThumbnailData.thumbnail.getHeight() - - (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale; + (thumbnailInsets.top + thumbnailInsets.bottom) * scale; + final float thumbnailScale; - final DeviceProfile profile = BaseActivity.fromContext(getContext()) - .getDeviceProfile(); + final DeviceProfile profile = mActivity.getDeviceProfile(); + if (getMeasuredWidth() == 0) { // If we haven't measured , skip the thumbnail drawing and only draw the background // color thumbnailScale = 0f; } else { final Configuration configuration = - getContext().getApplicationContext().getResources().getConfiguration(); - if (configuration.orientation == mThumbnailData.orientation) { - // If we are in the same orientation as the screenshot, just scale it to the - // width of the task view - thumbnailScale = getMeasuredWidth() / thumbnailWidth; - } else { - if (FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION) { - rotate = true; - // Scale the height (will be width after rotation) to the width of this view - thumbnailScale = getMeasuredWidth() / thumbnailHeight; - } else { - if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { - // Scale the landscape thumbnail up to app size, then scale that to the - // task view size to match other portrait screenshots - thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx); - } else { - // Otherwise, scale the screenshot to fit 1:1 in the current orientation - thumbnailScale = 1; - } - } - } + getContext().getResources().getConfiguration(); + // Rotate the screenshot if not in multi-window mode + rotate = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION && + configuration.orientation != mThumbnailData.orientation && + !mActivity.isInMultiWindowModeCompat(); + // Scale the screenshot to always fit the width of the card. + thumbnailScale = rotate + ? getMeasuredWidth() / thumbnailHeight + : getMeasuredWidth() / thumbnailWidth; } + if (rotate) { int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1; mMatrix.setRotate(90 * rotationDir); - Rect thumbnailInsets = mThumbnailData.insets; int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top; int newTopInset = rotationDir == 1 ? thumbnailInsets.left : thumbnailInsets.right; mMatrix.postTranslate(-newLeftInset * scale, -newTopInset * scale); @@ -209,27 +216,11 @@ public class TaskThumbnailView extends View { mMatrix.postScale(thumbnailScale, thumbnailScale); mBitmapShader.setLocalMatrix(mMatrix); - Shader shader = mBitmapShader; - if (!FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION) { - float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); - if (Math.round(bitmapHeight) < getMeasuredHeight()) { - int color = mPaint.getColor(); - LinearGradient fade = new LinearGradient( - 0, bitmapHeight - mFadeLength, 0, bitmapHeight, - color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); - shader = new ComposeShader(fade, shader, Mode.DST_OVER); - } - - float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0); - if (Math.round(bitmapWidth) < getMeasuredWidth()) { - int color = mPaint.getColor(); - LinearGradient fade = new LinearGradient( - bitmapWidth - mFadeLength, 0, bitmapWidth, 0, - color & 0x00FFFFFF, color, Shader.TileMode.CLAMP); - shader = new ComposeShader(fade, shader, Mode.DST_OVER); - } + float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); + if (Math.round(bitmapHeight) < getMeasuredHeight()) { + mClipBottom = bitmapHeight; } - mPaint.setShader(shader); + mPaint.setShader(mBitmapShader); } if (rotate) { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6f35752601..4deed73b69 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -41,7 +41,7 @@ public class DeviceProfile { public final boolean transposeLayoutWithOrientation; // Device properties in current orientation - private final boolean isLandscape; + public final boolean isLandscape; public final boolean isMultiWindowMode; public final int widthPx; From 6270a0ea18d27952fec20da04d64ca4f7e223849 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 6 Apr 2018 14:22:46 -0700 Subject: [PATCH 77/81] When dragging past first or last state, don't reinit target Example bug: 1. Swipe up to overview and let go 2. Swipe all the way to the top of the screen, past where all apps stops 3. Swipe down Before this change, you get reset in NORMAL state instead of OVERVIEW. By ensuring that getTargetState() checks the drag direction before returning a new state, we guarantee we only re-init in the case that the state is actually changing. Otherwise it's possible to change the state to one that is impossible, such as NORMAL when swiping up from ALL APPS. Change-Id: I19913dded9c94228d06289780b6400e99403f378 --- .../uioverrides/LandscapeStatesTouchController.java | 5 +++-- .../uioverrides/PortraitStatesTouchController.java | 2 +- .../touch/AbstractStateChangeTouchController.java | 4 ++++ .../launcher3/uioverrides/AllAppsSwipeController.java | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java index 355b88d910..30ceb43f93 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java @@ -60,12 +60,13 @@ public class LandscapeStatesTouchController extends PortraitStatesTouchControlle @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - if (fromState == ALL_APPS) { + if (fromState == ALL_APPS && !isDragTowardPositive) { // Should swipe down go to OVERVIEW instead? return TouchInteractionService.isConnected() ? mLauncher.getStateManager().getLastState() : NORMAL; - } else { + } else if (isDragTowardPositive) { return ALL_APPS; } + return fromState; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index 1b65ca0b05..c92264f3a8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -140,7 +140,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - if (fromState == ALL_APPS) { + if (fromState == ALL_APPS && !isDragTowardPositive) { // Should swipe down go to OVERVIEW instead? return TouchInteractionService.isConnected() ? mLauncher.getStateManager().getLastState() : NORMAL; diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 9726704ddb..3d85ac3c6d 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -124,6 +124,10 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene return mLauncher.getAllAppsController().getShiftRange(); } + /** + * Returns the state to go to from fromState given the drag direction. If there is no state in + * that direction, returns fromState. + */ protected abstract LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive); diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java index c97c3ccecb..d1cddc18f6 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java @@ -54,7 +54,12 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - return fromState == ALL_APPS ? NORMAL : ALL_APPS; + if (fromState == NORMAL && isDragTowardPositive) { + return ALL_APPS; + } else if (fromState == ALL_APPS && !isDragTowardPositive) { + return NORMAL; + } + return fromState; } @Override From 9bd862e588aad4971f0f4383412b20ddeb0ff4b4 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 6 Apr 2018 12:25:10 -0700 Subject: [PATCH 78/81] Log dismissing or launching recent tasks We now pass the log action (e.g. SWIPE or FLING) to the pending animation, so that the end listener can log appropriately. This is used when swiping down or up on a task, for example. Bug: 73783784 Change-Id: I5c2eee24e8b23cf4af68d503d3435a6d8088dd8a --- .../PortraitStatesTouchController.java | 3 +- .../uioverrides/TaskViewTouchController.java | 13 ++------- .../src/com/android/quickstep/TaskUtils.java | 5 ++++ .../android/quickstep/views/RecentsView.java | 29 ++++++++++++++----- .../com/android/quickstep/views/TaskView.java | 12 +++++++- .../logging/UserEventDispatcher.java | 24 ++++++++------- .../AbstractStateChangeTouchController.java | 20 ++++++------- .../launcher3/util/PendingAnimation.java | 20 +++++++++---- 8 files changed, 81 insertions(+), 45 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java index 1b65ca0b05..59715769d2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java @@ -37,6 +37,7 @@ import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.util.SysuiEventLogger; @@ -182,7 +183,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); mPendingAnimation = null; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index e73b2197fb..84a60bd9a0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -30,11 +30,10 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.touch.SwipeDetector; -import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; -import com.android.launcher3.util.PendingAnimation; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -152,7 +151,7 @@ public abstract class TaskViewTouchController mCurrentAnimation.setPlayFraction(0); } if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); mPendingAnimation = null; } @@ -249,15 +248,9 @@ public abstract class TaskViewTouchController private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) { if (mPendingAnimation != null) { - mPendingAnimation.finish(wasSuccess); + mPendingAnimation.finish(wasSuccess, logAction); mPendingAnimation = null; } - if (wasSuccess) { - if (!mCurrentAnimationIsGoingUp) { - mActivity.getUserEventDispatcher().logTaskLaunch(logAction, - Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); - } - } mDetector.finishedScrolling(); mTaskBeingDragged = null; mCurrentAnimation = null; diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java index 2df951b86e..5bf1d07db4 100644 --- a/quickstep/src/com/android/quickstep/TaskUtils.java +++ b/quickstep/src/com/android/quickstep/TaskUtils.java @@ -24,6 +24,7 @@ import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.util.ComponentKey; import com.android.systemui.shared.recents.model.Task; /** @@ -48,4 +49,8 @@ public class TaskUtils { return userManagerCompat.getBadgedLabelForUser( applicationInfo.loadLabel(packageManager), user); } + + public static ComponentKey getComponentKeyForTask(Task.TaskKey taskKey) { + return new ComponentKey(taskKey.getComponent(), UserHandle.of(taskKey.userId)); + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index d95619c055..b22e2b68e1 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -59,12 +59,15 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsModel; +import com.android.quickstep.TaskUtils; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoader; import com.android.systemui.shared.recents.model.Task; @@ -324,7 +327,7 @@ public abstract class RecentsView private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) { if (mPendingAnimation != null) { - mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan)); + mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(loadPlan)); return; } TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; @@ -748,10 +751,16 @@ public abstract class RecentsView } mPendingAnimation = pendingAnimation; - mPendingAnimation.addEndListener((isSuccess) -> { - if (isSuccess) { + mPendingAnimation.addEndListener((onEndListener) -> { + if (onEndListener.isSuccess) { if (removeTask) { - ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id); + Task task = taskView.getTask(); + if (task != null) { + ActivityManagerWrapper.getInstance().removeTask(task.key.id); + mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( + onEndListener.logAction, Direction.UP, + TaskUtils.getComponentKeyForTask(task.key)); + } } removeView(taskView); if (getChildCount() == 0) { @@ -793,7 +802,7 @@ public abstract class RecentsView AnimatorPlaybackController controller = AnimatorPlaybackController.wrap( pendingAnim.anim, DISMISS_TASK_DURATION); controller.dispatchOnStart(); - controller.setEndAction(() -> pendingAnim.finish(true)); + controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE)); controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN); controller.start(); } @@ -1050,9 +1059,15 @@ public abstract class RecentsView anim.setDuration(duration); mPendingAnimation = new PendingAnimation(anim); - mPendingAnimation.addEndListener((isSuccess) -> { - if (isSuccess) { + mPendingAnimation.addEndListener((onEndListener) -> { + if (onEndListener.isSuccess) { tv.launchTask(false); + Task task = tv.getTask(); + if (task != null) { + mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( + onEndListener.logAction, Direction.DOWN, + TaskUtils.getComponentKeyForTask(task.key)); + } } else { resetTaskVisuals(); } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 42da472b5c..c04f825f9b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -31,11 +31,15 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; +import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.TaskSystemShortcut; +import com.android.quickstep.TaskUtils; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; import com.android.systemui.shared.recents.model.Task; @@ -82,7 +86,13 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback public TaskView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - setOnClickListener((view) -> launchTask(true /* animate */)); + setOnClickListener((view) -> { + if (mTask != null) { + launchTask(true /* animate */); + BaseActivity.fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss( + Touch.TAP, Direction.NONE, TaskUtils.getComponentKeyForTask(mTask.key)); + } + }); setOutlineProvider(new TaskOutlineProvider(getResources())); } diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index 90355bd67c..bf870cca01 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -16,6 +16,14 @@ package com.android.launcher3.logging; +import static com.android.launcher3.logging.LoggerUtils.newCommandAction; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; +import static com.android.launcher3.logging.LoggerUtils.newDropTarget; +import static com.android.launcher3.logging.LoggerUtils.newItemTarget; +import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; +import static com.android.launcher3.logging.LoggerUtils.newTarget; +import static com.android.launcher3.logging.LoggerUtils.newTouchAction; + import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -38,20 +46,13 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.LogConfig; import java.util.Locale; import java.util.UUID; -import static com.android.launcher3.logging.LoggerUtils.newCommandAction; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.logging.LoggerUtils.newDropTarget; -import static com.android.launcher3.logging.LoggerUtils.newItemTarget; -import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; -import static com.android.launcher3.logging.LoggerUtils.newTarget; -import static com.android.launcher3.logging.LoggerUtils.newTouchAction; - /** * Manages the creation of {@link LauncherEvent}. * To debug this class, execute following command before side loading a new apk. @@ -162,14 +163,15 @@ public class UserEventDispatcher { dispatchUserEvent(event, intent); } - public void logTaskLaunch(int action, int direction, ComponentName componentName){ - LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE + public void logTaskLaunchOrDismiss(int action, int direction, ComponentKey componentKey) { + LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE or FLING newTarget(Target.Type.ITEM)); if (action == Action.Touch.SWIPE || action == Action.Touch.FLING) { + // Direction DOWN means the task was launched, UP means it was dismissed. event.action.dir = direction; } event.srcTarget[0].itemType = LauncherLogProto.ItemType.TASK; - fillComponentInfo(event.srcTarget[0], componentName); + fillComponentInfo(event.srcTarget[0], componentKey.componentName); dispatchUserEvent(event, null); } diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 9726704ddb..c875cf9bc7 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -246,24 +246,24 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene } protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { - if (targetState != mFromState) { - // Transition complete. log the action - mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, - getDirectionForLog(), - mStartContainerType, - mFromState.containerType, - mToState.containerType, - mLauncher.getWorkspace().getCurrentPage()); - } clearState(); boolean shouldGoToTargetState = true; if (mPendingAnimation != null) { boolean reachedTarget = mToState == targetState; - mPendingAnimation.finish(reachedTarget); + mPendingAnimation.finish(reachedTarget, logAction); mPendingAnimation = null; shouldGoToTargetState = !reachedTarget; } if (shouldGoToTargetState) { + if (targetState != mFromState) { + // Transition complete. log the action + mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, + getDirectionForLog(), + mStartContainerType, + mFromState.containerType, + mToState.containerType, + mLauncher.getWorkspace().getCurrentPage()); + } mLauncher.getStateManager().goToState(targetState, false /* animated */); } } diff --git a/src/com/android/launcher3/util/PendingAnimation.java b/src/com/android/launcher3/util/PendingAnimation.java index 4116d56e1d..617a38bbed 100644 --- a/src/com/android/launcher3/util/PendingAnimation.java +++ b/src/com/android/launcher3/util/PendingAnimation.java @@ -32,7 +32,7 @@ import java.util.function.Consumer; @TargetApi(Build.VERSION_CODES.O) public class PendingAnimation { - private final ArrayList> mEndListeners = new ArrayList<>(); + private final ArrayList> mEndListeners = new ArrayList<>(); public final AnimatorSet anim; @@ -40,14 +40,24 @@ public class PendingAnimation { this.anim = anim; } - public void finish(boolean isSuccess) { - for (Consumer listeners : mEndListeners) { - listeners.accept(isSuccess); + public void finish(boolean isSuccess, int logAction) { + for (Consumer listeners : mEndListeners) { + listeners.accept(new OnEndListener(isSuccess, logAction)); } mEndListeners.clear(); } - public void addEndListener(Consumer listener) { + public void addEndListener(Consumer listener) { mEndListeners.add(listener); } + + public static class OnEndListener { + public boolean isSuccess; + public int logAction; + + public OnEndListener(boolean isSuccess, int logAction) { + this.isSuccess = isSuccess; + this.logAction = logAction; + } + } } From f4beeb8dfbf88379a772f90d63783c0ce7805092 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Wed, 4 Apr 2018 17:36:51 +0200 Subject: [PATCH 79/81] Enable early wakeup during transitions We hit GL comp likely on some devices so we start composing earlier to avoid jank. Bug: 75985430 Change-Id: I94ff218c79fb512002a2fb7f8aa600d6662f269e --- quickstep/libs/sysui_shared.jar | Bin 119538 -> 120304 bytes .../LauncherAppTransitionManagerImpl.java | 3 +++ .../quickstep/util/ClipAnimationHelper.java | 1 + 3 files changed, 4 insertions(+) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index b75a1930654cac043efecffa1ed137e52b6f9de2..cebeea2b46cd952d12d0c41746a1870c6f1c7d3b 100644 GIT binary patch delta 13523 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 afK2F*vj8%tA&enR1``a-<7&ugVEzvkzVD#` delta 12803 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 diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index a2567c885a..ad0b7344b6 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -363,6 +363,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag t.show(target.leash); } } + t.setEarlyWakeup(); t.apply(); matrix.reset(); @@ -636,6 +637,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag t.show(target.leash); } } + t.setEarlyWakeup(); t.apply(); matrix.reset(); @@ -763,6 +765,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag t.show(app.leash); } } + t.setEarlyWakeup(); t.apply(); matrix.reset(); diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java index 0f895b851f..493e9e2386 100644 --- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -121,6 +121,7 @@ public class ClipAnimationHelper { transaction.show(app.leash); } } + transaction.setEarlyWakeup(); transaction.apply(); } From 926ba83726b65e9abb013ba9f72992c6128c8681 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 9 Apr 2018 09:23:11 -0700 Subject: [PATCH 80/81] Elevate GPU priority of Launcher3Quickstep Bug: 75985430 Change-Id: I4ac70c76db98b4ab666b0559f3185392142be045 --- proguard.flags | 5 +++ quickstep/res/values/override.xml | 2 ++ .../QuickstepProcessInitializer.java | 34 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java diff --git a/proguard.flags b/proguard.flags index 086337dfa2..e9f6db462e 100644 --- a/proguard.flags +++ b/proguard.flags @@ -107,6 +107,11 @@ public (...); } +# MainProcessInitializer +-keep class com.android.quickstep.QuickstepProcessInitializer { + public (...); +} + -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** { *; } diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml index 2bd9f8f6f3..d6836594f4 100644 --- a/quickstep/res/values/override.xml +++ b/quickstep/res/values/override.xml @@ -18,5 +18,7 @@ com.android.launcher3.LauncherAppTransitionManagerImpl com.android.quickstep.InstantAppResolverImpl + + com.android.quickstep.QuickstepProcessInitializer diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java new file mode 100644 index 0000000000..aed9959576 --- /dev/null +++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 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 android.content.Context; + +import com.android.launcher3.MainProcessInitializer; +import com.android.systemui.shared.system.ThreadedRendererCompat; + +public class QuickstepProcessInitializer extends MainProcessInitializer { + + public QuickstepProcessInitializer(Context context) { } + + @Override + protected void init(Context context) { + super.init(context); + + // Elevate GPU priority for Quickstep and Remote animations. + ThreadedRendererCompat.setContextPriority(ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG); + } +} From df336cf685c9d85e1e5ce5c8a5048e71322b22f3 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 9 Apr 2018 10:05:04 -0700 Subject: [PATCH 81/81] Making QuickScrub work, when the fallback activity is on top Bug: 75979063 Change-Id: If8029901ad1f99551b3eba74620616edf6f993ef --- .../quickstep/ActivityControlHelper.java | 48 ++++++++++--- .../quickstep/TouchInteractionService.java | 69 +++++++++++-------- 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index d82b8f437c..97930f898a 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -35,7 +35,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.AllAppsTransitionController; @@ -61,7 +60,13 @@ public interface ActivityControlHelper { void onQuickstepGestureStarted(T activity, boolean activityVisible); - void onQuickInteractionStart(T activity, boolean activityVisible); + /** + * Updates the UI to indicate quick interaction. + * @return true if there any any UI change as a result of this + */ + boolean onQuickInteractionStart(T activity, boolean activityVisible); + + void executeOnWindowAvailable(T activity, Runnable action); void executeOnNextDraw(T activity, TaskView targetView, Runnable action); @@ -82,6 +87,9 @@ public interface ActivityControlHelper { void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver, final RecentsAnimationListener remoteAnimationListener); + @Nullable + T getCreatedActivity(); + @UiThread @Nullable RecentsView getVisibleRecentsView(); @@ -102,8 +110,18 @@ public interface ActivityControlHelper { } @Override - public void onQuickInteractionStart(Launcher activity, boolean activityVisible) { + public boolean onQuickInteractionStart(Launcher activity, boolean activityVisible) { + LauncherState fromState = activity.getStateManager().getState(); activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible); + return !fromState.overviewUi; + } + + @Override + public void executeOnWindowAvailable(Launcher activity, Runnable action) { + if (activity.getWorkspace().runOnOverlayHidden(action)) { + // Notify the activity that qiuckscrub has started + onQuickstepGestureStarted(activity, true); + } } @Override @@ -209,8 +227,8 @@ public interface ActivityControlHelper { } @Nullable - @UiThread - private Launcher getLauncher() { + @Override + public Launcher getCreatedActivity() { LauncherAppState app = LauncherAppState.getInstanceNoCreate(); if (app == null) { return null; @@ -221,7 +239,7 @@ public interface ActivityControlHelper { @Nullable @UiThread private Launcher getVisibleLaucher() { - Launcher launcher = getLauncher(); + Launcher launcher = getCreatedActivity(); return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ? launcher : null; } @@ -253,8 +271,14 @@ public interface ActivityControlHelper { } @Override - public void onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) { - // TODO: + public boolean onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) { + // Activity does not need any UI change for quickscrub. + return false; + } + + @Override + public void executeOnWindowAvailable(RecentsActivity activity, Runnable action) { + action.run(); } @Override @@ -336,10 +360,16 @@ public interface ActivityControlHelper { intent, assistDataReceiver, remoteAnimationListener, null, null); } + @Nullable + @Override + public RecentsActivity getCreatedActivity() { + return RecentsActivityTracker.getCurrentActivity(); + } + @Nullable @Override public RecentsView getVisibleRecentsView() { - RecentsActivity activity = RecentsActivityTracker.getCurrentActivity(); + RecentsActivity activity = getCreatedActivity(); if (activity != null && activity.hasWindowFocus()) { return activity.getOverviewPanel(); } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index b610f4d424..84d8983e03 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -21,8 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; -import static com.android.launcher3.LauncherState.FAST_OVERVIEW; -import static com.android.launcher3.LauncherState.NORMAL; + import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE; import android.annotation.TargetApi; @@ -43,9 +42,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherState; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; import com.android.launcher3.util.TraceHelper; @@ -220,13 +217,13 @@ public class TouchInteractionService extends Service { private TouchConsumer getCurrentTouchConsumer( @HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) { - RunningTaskInfo runningTaskInfo = mAM.getRunningTask(); + RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0); if (runningTaskInfo == null && !forceToLauncher) { return mNoOpTouchConsumer; } else if (forceToLauncher || runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) { - return getLauncherConsumer(); + return getOverviewConsumer(); } else { if (tracker == null) { tracker = VelocityTracker.obtain(); @@ -238,18 +235,20 @@ public class TouchInteractionService extends Service { } } - private TouchConsumer getLauncherConsumer() { - Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback(); - if (launcher == null) { + private TouchConsumer getOverviewConsumer() { + ActivityControlHelper activityHelper = mOverviewCommandHelper.getActivityControlHelper(); + BaseDraggingActivity activity = activityHelper.getCreatedActivity(); + if (activity == null) { return mNoOpTouchConsumer; } - View target = launcher.getDragLayer(); - return new LauncherTouchConsumer(launcher, target); + return new OverviewTouchConsumer(activityHelper, activity); } - private static class LauncherTouchConsumer implements TouchConsumer { + private static class OverviewTouchConsumer + implements TouchConsumer { - private final Launcher mLauncher; + private final ActivityControlHelper mActivityHelper; + private final T mActivity; private final View mTarget; private final int[] mLocationOnScreen = new int[2]; private final PointF mDownPos = new PointF(); @@ -260,12 +259,17 @@ public class TouchInteractionService extends Service { private boolean mInvalidated = false; private boolean mHadWindowFocusOnDown; - LauncherTouchConsumer(Launcher launcher, View target) { - mLauncher = launcher; - mTarget = target; + private float mLastProgress = 0; + private boolean mStartPending = false; + private boolean mEndPending = false; + + OverviewTouchConsumer(ActivityControlHelper activityHelper, T activity) { + mActivityHelper = activityHelper; + mActivity = activity; + mTarget = activity.getDragLayer(); mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop(); - mQuickScrubController = mLauncher.getOverviewPanel() + mQuickScrubController = mActivity.getOverviewPanel() .getQuickScrubController(); } @@ -327,16 +331,22 @@ public class TouchInteractionService extends Service { return; } if (interactionType == INTERACTION_QUICK_SCRUB) { + mStartPending = true; + Runnable action = () -> { - LauncherState fromState = mLauncher.getStateManager().getState(); - mLauncher.getStateManager().goToState(FAST_OVERVIEW, true); - mQuickScrubController.onQuickScrubStart(fromState == NORMAL); + mQuickScrubController.onQuickScrubStart( + mActivityHelper.onQuickInteractionStart(mActivity, true)); + mQuickScrubController.onQuickScrubProgress(mLastProgress); + mStartPending = false; + + if (mEndPending) { + mQuickScrubController.onQuickScrubEnd(); + mEndPending = false; + } + }; - if (mLauncher.getWorkspace().runOnOverlayHidden(action)) { - // Hide the minus one overlay so launcher can get window focus. - mLauncher.onQuickstepGestureStarted(true); - } + mActivityHelper.executeOnWindowAvailable(mActivity, action); } } @@ -345,12 +355,17 @@ public class TouchInteractionService extends Service { if (mInvalidated) { return; } - mQuickScrubController.onQuickScrubEnd(); + if (mStartPending) { + mEndPending = true; + } else { + mQuickScrubController.onQuickScrubEnd(); + } } @Override public void onQuickScrubProgress(float progress) { - if (mInvalidated) { + mLastProgress = progress; + if (mInvalidated || mEndPending) { return; } mQuickScrubController.onQuickScrubProgress(progress);