Merge "Support two line text in AllApps/OnDeviceSearch w/ feature flag" into tm-qpr-dev
diff --git a/quickstep/res/values-sw600dp/config.xml b/quickstep/res/values-sw600dp/config.xml
new file mode 100644
index 0000000..e1e442f
--- /dev/null
+++ b/quickstep/res/values-sw600dp/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Applies to large tablet screens portrait -->
+<resources>
+ <!-- Taskbar -->
+ <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
+ <bool name="start_align_taskbar">true</bool>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp-land/config.xml b/quickstep/res/values-sw720dp-land/config.xml
new file mode 100644
index 0000000..bf0f9ad
--- /dev/null
+++ b/quickstep/res/values-sw720dp-land/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Applies to large tablet screens landscape -->
+<resources>
+ <!-- Taskbar -->
+ <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
+ <bool name="start_align_taskbar">false</bool>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp/config.xml b/quickstep/res/values-sw720dp/config.xml
new file mode 100644
index 0000000..e1e442f
--- /dev/null
+++ b/quickstep/res/values-sw720dp/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Applies to large tablet screens portrait -->
+<resources>
+ <!-- Taskbar -->
+ <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
+ <bool name="start_align_taskbar">true</bool>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index d581582..b61bdfb 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -51,4 +51,8 @@
</item>
<string name="setup_wizard_pkg" translatable="false" />
+
+ <!-- Taskbar -->
+ <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
+ <bool name="start_align_taskbar">false</bool>
</resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index f5d7f3b..8c21778 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static android.view.HapticFeedbackConstants.LONG_PRESS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
@@ -43,6 +44,7 @@
import android.view.InsetsController;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
@@ -189,6 +191,7 @@
// Stashed handle properties.
private MultiProperty mTaskbarStashedHandleAlpha;
private AnimatedFloat mTaskbarStashedHandleHintScale;
+ private final AccessibilityManager mAccessibilityManager;
/** Whether we are currently visually stashed (might change based on launcher state). */
private boolean mIsStashed = false;
@@ -221,6 +224,7 @@
mActivity = activity;
mPrefs = LauncherPrefs.getPrefs(mActivity);
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
+ mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
if (isPhoneMode()) {
// DeviceProfile's taskbar vars aren't initialized w/ the flag off
Resources resources = mActivity.getResources();
@@ -1018,7 +1022,15 @@
cancelTimeoutIfExists();
mTimeoutAlarm.setOnAlarmListener(this::onTaskbarTimeout);
- mTimeoutAlarm.setAlarm(NO_TOUCH_TIMEOUT_TO_STASH_MS);
+ mTimeoutAlarm.setAlarm(getTaskbarAutoHideTimeout());
+ }
+
+ /**
+ * returns appropriate timeout for taskbar to stash depending on accessibility being on/off.
+ */
+ private long getTaskbarAutoHideTimeout() {
+ return mAccessibilityManager.getRecommendedTimeoutMillis((int) NO_TOUCH_TIMEOUT_TO_STASH_MS,
+ FLAG_CONTENT_CONTROLS);
}
private void onTaskbarTimeout(Alarm alarm) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 11b07e8..e66856a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -94,6 +94,8 @@
private float mTransientTaskbarAllAppsButtonTranslationXOffset;
+ private final boolean mStartAlignTaskbar;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -121,6 +123,8 @@
resources.getDimension(isTransientTaskbar
? R.dimen.transient_taskbar_all_apps_button_translation_x_offset
: R.dimen.taskbar_all_apps_button_translation_x_offset);
+ mStartAlignTaskbar = mActivityContext.isThreeButtonNav()
+ && resources.getBoolean(R.bool.start_align_taskbar);
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
@@ -372,10 +376,22 @@
boolean needMoreSpaceForNav = layoutRtl ?
navSpaceNeeded > (iconEnd - spaceNeeded) :
iconEnd > (right - navSpaceNeeded);
- if (needMoreSpaceForNav) {
- int offset = layoutRtl ?
- navSpaceNeeded - (iconEnd - spaceNeeded) :
- (right - navSpaceNeeded) - iconEnd;
+
+ if (mStartAlignTaskbar) {
+ // Taskbar is aligned to the start
+ int startSpacingPx = deviceProfile.inlineNavButtonsEndSpacingPx;
+
+ if (layoutRtl) {
+ iconEnd = right - startSpacingPx;
+ } else {
+ iconEnd = startSpacingPx + spaceNeeded;
+ }
+ } else if (needMoreSpaceForNav) {
+ // Add offset to account for nav bar when taskbar is centered
+ int offset = layoutRtl
+ ? navSpaceNeeded - (iconEnd - spaceNeeded)
+ : (right - navSpaceNeeded) - iconEnd;
+
iconEnd += offset;
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
new file mode 100644
index 0000000..6dd67de
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.quickstep.util
+
+import android.animation.ObjectAnimator
+import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
+import android.view.View
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
+import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskView
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import java.util.function.Supplier
+
+/**
+ * Utils class to help run animations for initiating split screen from launcher.
+ * Will be expanded with future refactors. Works in conjunction with the state stored in
+ * [SplitSelectStateController]
+ */
+class SplitAnimationController(val splitSelectStateController: SplitSelectStateController) {
+ companion object {
+ // Break this out into maybe enums? Abstractions into its own classes? Tbd.
+ data class SplitAnimInitProps(
+ val originalView: View,
+ val originalBitmap: Bitmap?,
+ val iconDrawable: Drawable,
+ val fadeWithThumbnail: Boolean,
+ val isStagedTask: Boolean,
+ val iconView: View?
+ )
+ }
+
+ /**
+ * Returns different elements to animate for the initial split selection animation
+ * depending on the state of the surface from which the split was initiated
+ */
+ fun getFirstAnimInitViews(taskViewSupplier: Supplier<TaskView>,
+ splitSelectSourceSupplier: Supplier<SplitSelectSource>)
+ : SplitAnimInitProps {
+ if (!splitSelectStateController.isAnimateCurrentTaskDismissal) {
+ // Initiating from home
+ val splitSelectSource = splitSelectSourceSupplier.get()
+ return SplitAnimInitProps(splitSelectSource.view, originalBitmap = null,
+ splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true,
+ iconView = null)
+ } else if (splitSelectStateController.isDismissingFromSplitPair) {
+ // Initiating split from overview, but on a split pair
+ val taskView = taskViewSupplier.get()
+ for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
+ if (container.task.key.id == splitSelectStateController.initialTaskId) {
+ return SplitAnimInitProps(container.thumbnailView,
+ container.thumbnailView.thumbnail, container.iconView.drawable!!,
+ fadeWithThumbnail = true, isStagedTask = true,
+ iconView = container.iconView
+ )
+ }
+ }
+ throw IllegalStateException("Attempting to init split from existing split pair " +
+ "without a valid taskIdAttributeContainer")
+ } else {
+ // Initiating split from overview on fullscreen task TaskView
+ val taskView = taskViewSupplier.get()
+ return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
+ taskView.iconView.drawable!!, fadeWithThumbnail = true, isStagedTask = true,
+ taskView.iconView
+ )
+ }
+ }
+
+ /**
+ * When selecting first app from split pair, second app's thumbnail remains. This animates
+ * the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying
+ * it with [TaskThumbnailView]'s splashView. Adds animations to the provided builder.
+ * Note: The app that **was not** selected as the first split app should be the container that's
+ * passed through.
+ *
+ * @param builder Adds animation to this
+ * @param taskIdAttributeContainer container of the app that **was not** selected
+ * @param isPrimaryTaskSplitting if true, task that was split would be top/left in the pair
+ * (opposite of that representing [taskIdAttributeContainer])
+ */
+ fun addInitialSplitFromPair(taskIdAttributeContainer: TaskIdAttributeContainer,
+ builder: PendingAnimation, deviceProfile: DeviceProfile,
+ taskViewWidth: Int, taskViewHeight: Int,
+ isPrimaryTaskSplitting: Boolean) {
+ val thumbnail = taskIdAttributeContainer.thumbnailView
+ val iconView: View = taskIdAttributeContainer.iconView
+ builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
+ thumbnail.setShowSplashForSplitSelection(true)
+ if (deviceProfile.isLandscape) {
+ // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
+ val centerThumbnailTranslationX: Float = (taskViewWidth - thumbnail.width) / 2f
+ val centerIconTranslationX: Float = (taskViewWidth - iconView.width) / 2f
+ val finalScaleX: Float = taskViewWidth.toFloat() / thumbnail.width
+ builder.add(ObjectAnimator.ofFloat(thumbnail,
+ TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, centerThumbnailTranslationX))
+ // icons are anchored from Gravity.END, so need to use negative translation
+ builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X,
+ -centerIconTranslationX))
+ builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_X, finalScaleX))
+
+ // Reset other dimensions
+ // TODO(b/271468547), can't set Y translate to 0, need to account for top space
+ thumbnail.scaleY = 1f
+ val translateYResetVal: Float = if (!isPrimaryTaskSplitting) 0f else
+ deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
+ builder.add(ObjectAnimator.ofFloat(thumbnail,
+ TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+ translateYResetVal))
+ } else {
+ val thumbnailSize = taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+ // Center view first so scaling happens uniformly, alternatively we can move pivotY to 0
+ // primary thumbnail has layout margin above it, so secondary thumbnail needs to take
+ // that into account. We should migrate to only using translations otherwise this
+ // asymmetry causes problems..
+
+ // Icon defaults to center | horizontal, we add additional translation for split
+ val centerIconTranslationX = 0f
+ var centerThumbnailTranslationY: Float
+
+ // TODO(b/271468547), primary thumbnail has layout margin above it, so secondary
+ // thumbnail needs to take that into account. We should migrate to only using
+ // translations otherwise this asymmetry causes problems..
+ if (isPrimaryTaskSplitting) {
+ centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
+ centerThumbnailTranslationY += deviceProfile.overviewTaskThumbnailTopMarginPx
+ .toFloat()
+ } else {
+ centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
+ }
+ val finalScaleY: Float = thumbnailSize.toFloat() / thumbnail.height
+ builder.add(ObjectAnimator.ofFloat(thumbnail,
+ TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, centerThumbnailTranslationY))
+
+ // icons are anchored from Gravity.END, so need to use negative translation
+ builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X,
+ centerIconTranslationX))
+ builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_Y, finalScaleY))
+
+ // Reset other dimensions
+ thumbnail.scaleX = 1f
+ builder.add(ObjectAnimator.ofFloat(thumbnail,
+ TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f))
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 5214f7c..1f4085f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -82,6 +82,7 @@
private final Context mContext;
private final Handler mHandler;
private final RecentsModel mRecentTasksModel;
+ private final SplitAnimationController mSplitAnimationController;
private StatsLogManager mStatsLogManager;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
@@ -96,6 +97,11 @@
private boolean mRecentsAnimationRunning;
/** If {@code true}, animates the existing task view split placeholder view */
private boolean mAnimateCurrentTaskDismissal;
+ /**
+ * Acts as a subset of {@link #mAnimateCurrentTaskDismissal}, we can't be dismissing from a
+ * split pair task view without wanting to animate current task dismissal overall
+ */
+ private boolean mDismissingFromSplitPair;
@Nullable
private UserHandle mUser;
/** If not null, this is the TaskView we want to launch from */
@@ -116,6 +122,7 @@
mStateManager = stateManager;
mDepthController = depthController;
mRecentTasksModel = recentsModel;
+ mSplitAnimationController = new SplitAnimationController(this);
}
/**
@@ -399,6 +406,18 @@
mAnimateCurrentTaskDismissal = animateCurrentTaskDismissal;
}
+ public boolean isDismissingFromSplitPair() {
+ return mDismissingFromSplitPair;
+ }
+
+ public void setDismissingFromSplitPair(boolean dismissingFromSplitPair) {
+ mDismissingFromSplitPair = dismissingFromSplitPair;
+ }
+
+ public SplitAnimationController getSplitAnimationController() {
+ return mSplitAnimationController;
+ }
+
/**
* Requires Shell Transitions
*/
@@ -506,6 +525,7 @@
mItemInfo = null;
mSplitEvent = null;
mAnimateCurrentTaskDismissal = false;
+ mDismissingFromSplitPair = false;
}
/**
@@ -532,6 +552,10 @@
return mInitialTaskId;
}
+ public int getSecondTaskId() {
+ return mSecondTaskId;
+ }
+
private boolean isSecondTaskIntentSet() {
return (mSecondTaskId != INVALID_TASK_ID || mSecondTaskIntent != null);
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 5414068..ccc2df6 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -496,7 +496,7 @@
}
@Override
- void setThumbnailVisibility(int visibility) {
+ void setThumbnailVisibility(int visibility, int taskId) {
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
mSnapshotViewMap.valueAt(i).setVisibility(visibility);
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index e9498fd..0e05032 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -1,5 +1,7 @@
package com.android.quickstep.views;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -25,6 +27,7 @@
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -267,6 +270,19 @@
@Override
protected int getLastSelectedChildTaskIndex() {
+ SplitSelectStateController splitSelectController =
+ getRecentsView().getSplitSelectController();
+ if (splitSelectController.isDismissingFromSplitPair()) {
+ // return the container index of the task that wasn't initially selected to split with
+ // because that is the only remaining app that can be selected. The coordinate checks
+ // below aren't reliable since both of those views may be gone/transformed
+ int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
+ if (initSplitTaskId != INVALID_TASK_ID) {
+ return initSplitTaskId == mTask.key.id ? 1 : 0;
+ }
+ }
+
+ // Check which of the two apps was selected
if (isCoordInView(mIconView2, mLastTouchDownPosition)
|| isCoordInView(mSnapshotView2, mLastTouchDownPosition)) {
return 1;
@@ -296,9 +312,30 @@
if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
return;
}
- getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
- mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
- mActivity.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+ int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
+ if (initSplitTaskId == INVALID_TASK_ID) {
+ getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
+ mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
+ mActivity.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+ // Should we be having a separate translation step apart from the measuring above?
+ // The following only applies to large screen for now, but for future reference
+ // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
+ // translation directions
+ mSnapshotView.applySplitSelectTranslateX(mSnapshotView.getTranslationX());
+ mSnapshotView.applySplitSelectTranslateY(mSnapshotView.getTranslationY());
+ mSnapshotView2.applySplitSelectTranslateX(mSnapshotView2.getTranslationX());
+ mSnapshotView2.applySplitSelectTranslateY(mSnapshotView2.getTranslationY());
+ } else {
+ // Currently being split with this taskView, let the non-split selected thumbnail
+ // take up full thumbnail area
+ TaskIdAttributeContainer container =
+ mTaskIdAttributeContainer[initSplitTaskId == mTask.key.id ? 1 : 0];
+ container.getThumbnailView().measure(widthMeasureSpec,
+ View.MeasureSpec.makeMeasureSpec(
+ heightSize -
+ mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx,
+ MeasureSpec.EXACTLY));
+ }
updateIconPlacement();
}
@@ -379,21 +416,27 @@
mSnapshotView2.refreshSplashView();
}
+ @Override
+ protected void resetViewTransforms() {
+ super.resetViewTransforms();
+ mSnapshotView2.resetViewTransforms();
+ }
+
/**
- * Sets visibility for thumbnails and associated elements (DWB banners).
- * IconView is unaffected.
+ * Sets visibility for thumbnails and associated elements (DWB banners).
+ * IconView is unaffected.
*
- * When setting INVISIBLE, sets the visibility for the last selected child task.
- * When setting VISIBLE (as a reset), sets the visibility for both tasks.
+ * When setting INVISIBLE, sets the visibility for the last selected child task.
+ * When setting VISIBLE (as a reset), sets the visibility for both tasks.
*/
@Override
- void setThumbnailVisibility(int visibility) {
+ void setThumbnailVisibility(int visibility, int taskId) {
if (visibility == VISIBLE) {
mSnapshotView.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
mSnapshotView2.setVisibility(visibility);
mDigitalWellBeingToast2.setBannerVisibility(visibility);
- } else if (getLastSelectedChildTaskIndex() == 0) {
+ } else if (taskId == getTaskIds()[0]) {
mSnapshotView.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
} else {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 717300e..614ef81 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -184,6 +184,7 @@
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SurfaceTransaction;
@@ -192,6 +193,7 @@
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.VibrationConstants;
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -935,7 +937,7 @@
if (mHandleTaskStackChanges) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
- for (TaskView.TaskIdAttributeContainer container :
+ for (TaskIdAttributeContainer container :
taskView.getTaskIdAttributeContainers()) {
if (container == null || taskId != container.getTask().key.id) {
continue;
@@ -3099,29 +3101,26 @@
RectF startingTaskRect = new RectF();
safeRemoveDragLayerView(mFirstFloatingTaskView);
+ SplitAnimInitProps splitAnimInitProps =
+ mSplitSelectStateController.getSplitAnimationController().getFirstAnimInitViews(
+ () -> mSplitHiddenTaskView, () -> mSplitSelectSource);
if (mSplitSelectStateController.isAnimateCurrentTaskDismissal()) {
// Create the split select animation from Overview
- mSplitHiddenTaskView.setThumbnailVisibility(INVISIBLE);
- anim.setViewAlpha(mSplitHiddenTaskView.getIconView(), 0, clampToProgress(LINEAR,
+ mSplitHiddenTaskView.setThumbnailVisibility(INVISIBLE,
+ mSplitSelectStateController.getInitialTaskId());
+ anim.setViewAlpha(splitAnimInitProps.getIconView(), 0, clampToProgress(LINEAR,
timings.getIconFadeStartOffset(),
timings.getIconFadeEndOffset()));
- mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- mSplitHiddenTaskView.getThumbnail(),
- mSplitHiddenTaskView.getThumbnail().getThumbnail(),
- mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
- mFirstFloatingTaskView.setAlpha(1);
- mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
- true /* fadeWithThumbnail */, true /* isStagedTask */);
- } else {
- // Create the split select animation from Home
- mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- mSplitSelectSource.view, null /* thumbnail */,
- mSplitSelectSource.drawable, startingTaskRect);
- mFirstFloatingTaskView.setAlpha(1);
- mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
- false /* fadeWithThumbnail */, true /* isStagedTask */);
}
+ mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+ splitAnimInitProps.getOriginalView(),
+ splitAnimInitProps.getOriginalBitmap(),
+ splitAnimInitProps.getIconDrawable(), startingTaskRect);
+ mFirstFloatingTaskView.setAlpha(1);
+ mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
+ splitAnimInitProps.getFadeWithThumbnail(), splitAnimInitProps.isStagedTask());
+
// Allow user to click staged app to launch into fullscreen
if (ENABLE_LAUNCH_FROM_STAGED_APP.get()) {
mFirstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
@@ -4450,7 +4449,7 @@
mTaskViewsSecondarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
- if (taskView == mSplitHiddenTaskView) {
+ if (taskView == mSplitHiddenTaskView && !taskView.containsMultipleTasks()) {
continue;
}
taskView.getSecondarySplitTranslationProperty().set(taskView, translation);
@@ -4501,6 +4500,10 @@
mSplitHiddenTaskViewIndex = indexOfChild(mSplitHiddenTaskView);
mSplitSelectStateController
.setAnimateCurrentTaskDismissal(splitSelectSource.animateCurrentTaskDismissal);
+
+ // Prevent dismissing whole task if we're only initiating from one of 2 tasks in split pair
+ mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
+ && mSplitHiddenTaskView.containsMultipleTasks());
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
@@ -4519,8 +4522,32 @@
* Modifies a PendingAnimation with the animations for entering split staging
*/
public void createSplitSelectInitAnimation(PendingAnimation builder, int duration) {
- if (mSplitSelectStateController.isAnimateCurrentTaskDismissal()) {
- // Splitting from Overview
+ boolean isInitiatingSplitFromTaskView =
+ mSplitSelectStateController.isAnimateCurrentTaskDismissal();
+ boolean isInitiatingTaskViewSplitPair =
+ mSplitSelectStateController.isDismissingFromSplitPair();
+ if (isInitiatingSplitFromTaskView && isInitiatingTaskViewSplitPair) {
+ // Splitting from Overview for split pair task
+ createInitialSplitSelectAnimation(builder);
+
+ // Animate pair thumbnail into full thumbnail
+ boolean primaryTaskSelected =
+ mSplitHiddenTaskView.getTaskIdAttributeContainers()[0].getTask().key.id ==
+ mSplitSelectStateController.getInitialTaskId();
+ TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
+ .getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
+ TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
+ mSplitSelectStateController.getSplitAnimationController()
+ .addInitialSplitFromPair(taskIdAttributeContainer, builder,
+ mActivity.getDeviceProfile(),
+ mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
+ primaryTaskSelected);
+ builder.addOnFrameCallback(() ->{
+ thumbnail.refreshSplashView();
+ mSplitHiddenTaskView.updateSnapshotRadius();
+ });
+ } else if (isInitiatingSplitFromTaskView) {
+ // Splitting from Overview for fullscreen task
createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration,
true /* dismissingForSplitSelection*/);
} else {
@@ -4608,7 +4635,8 @@
mSecondSplitHiddenView = containerTaskView;
if (mSecondSplitHiddenView != null) {
- mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE);
+ mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE,
+ mSplitSelectStateController.getSecondTaskId());
}
InteractionJankMonitorWrapper.begin(this,
@@ -4634,7 +4662,7 @@
}
if (mSecondSplitHiddenView != null) {
- mSecondSplitHiddenView.setThumbnailVisibility(VISIBLE);
+ mSecondSplitHiddenView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
mSecondSplitHiddenView = null;
}
@@ -4660,7 +4688,7 @@
resetTaskVisuals();
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
- mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE);
+ mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
mSplitHiddenTaskView = null;
}
if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
@@ -5530,7 +5558,7 @@
}
taskView.setShowScreenshot(true);
- for (TaskView.TaskIdAttributeContainer container :
+ for (TaskIdAttributeContainer container :
taskView.getTaskIdAttributeContainers()) {
if (container == null) {
continue;
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 432eadc..62a58f5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -81,6 +81,47 @@
}
};
+ public static final Property<TaskThumbnailView, Float> SPLASH_ALPHA =
+ new FloatProperty<TaskThumbnailView>("splashAlpha") {
+ @Override
+ public void setValue(TaskThumbnailView thumbnail, float splashAlpha) {
+ thumbnail.setSplashAlpha(splashAlpha);
+ }
+
+ @Override
+ public Float get(TaskThumbnailView thumbnailView) {
+ return thumbnailView.mSplashAlpha / 255f;
+ }
+ };
+
+ /** Use to animate thumbnail translationX while first app in split selection is initiated */
+ public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_X =
+ new FloatProperty<TaskThumbnailView>("splitSelectTranslateX") {
+ @Override
+ public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateX) {
+ thumbnail.applySplitSelectTranslateX(splitSelectTranslateX);
+ }
+
+ @Override
+ public Float get(TaskThumbnailView thumbnailView) {
+ return thumbnailView.mSplitSelectTranslateX;
+ }
+ };
+
+ /** Use to animate thumbnail translationY while first app in split selection is initiated */
+ public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_Y =
+ new FloatProperty<TaskThumbnailView>("splitSelectTranslateY") {
+ @Override
+ public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateY) {
+ thumbnail.applySplitSelectTranslateY(splitSelectTranslateY);
+ }
+
+ @Override
+ public Float get(TaskThumbnailView thumbnailView) {
+ return thumbnailView.mSplitSelectTranslateY;
+ }
+ };
+
private final BaseActivity mActivity;
@Nullable
private TaskOverlay mOverlay;
@@ -111,6 +152,10 @@
private int mSplashAlpha = 0;
private boolean mOverlayEnabled;
+ /** Used as a placeholder when the original thumbnail animates out to. */
+ private boolean mShowSplashForSplitSelection;
+ private float mSplitSelectTranslateX;
+ private float mSplitSelectTranslateY;
public TaskThumbnailView(Context context) {
this(context, null);
@@ -342,10 +387,17 @@
// Draw splash above thumbnail to hide inconsistencies in rotation and aspect ratios.
if (shouldShowSplashView()) {
+ float cornerRadiusX = cornerRadius;
+ float cornerRadiusY = cornerRadius;
+ if (mShowSplashForSplitSelection) {
+ cornerRadiusX = cornerRadius / getScaleX();
+ cornerRadiusY = cornerRadius / getScaleY();
+ }
+
// Always draw background for hiding inconsistencies, even if splash view is not yet
// loaded (which can happen as task icons are loaded asynchronously in the background)
- canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadius,
- cornerRadius, mSplashBackgroundPaint);
+ canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadiusX,
+ cornerRadiusY, mSplashBackgroundPaint);
if (mSplashView != null) {
mSplashView.layout((int) x, (int) (y + 1), (int) width, (int) height - 1);
mSplashView.draw(canvas);
@@ -353,6 +405,31 @@
}
}
+ /** See {@link #SPLIT_SELECT_TRANSLATE_X} */
+ protected void applySplitSelectTranslateX(float splitSelectTranslateX) {
+ mSplitSelectTranslateX = splitSelectTranslateX;
+ applyTranslateX();
+ }
+
+ /** See {@link #SPLIT_SELECT_TRANSLATE_Y} */
+ protected void applySplitSelectTranslateY(float splitSelectTranslateY) {
+ mSplitSelectTranslateY = splitSelectTranslateY;
+ applyTranslateY();
+ }
+
+ private void applyTranslateX() {
+ setTranslationX(mSplitSelectTranslateX);
+ }
+
+ private void applyTranslateY() {
+ setTranslationY(mSplitSelectTranslateY);
+ }
+
+ protected void resetViewTransforms() {
+ mSplitSelectTranslateX = 0;
+ mSplitSelectTranslateY = 0;
+ }
+
public TaskView getTaskView() {
return (TaskView) getParent();
}
@@ -373,7 +450,12 @@
*/
public boolean shouldShowSplashView() {
return isThumbnailAspectRatioDifferentFromThumbnailData()
- || isThumbnailRotationDifferentFromTask();
+ || isThumbnailRotationDifferentFromTask()
+ || mShowSplashForSplitSelection;
+ }
+
+ public void setShowSplashForSplitSelection(boolean showSplashForSplitSelection) {
+ mShowSplashForSplitSelection = showSplashForSplitSelection;
}
protected void refreshSplashView() {
@@ -396,7 +478,6 @@
imageView.setScaleType(ImageView.ScaleType.MATRIX);
Matrix matrix = new Matrix();
-
float drawableWidth = mSplashViewDrawable.getIntrinsicWidth();
float drawableHeight = mSplashViewDrawable.getIntrinsicHeight();
float viewWidth = getMeasuredWidth();
@@ -408,12 +489,13 @@
float nonGridScale = getTaskView() == null ? 1 : 1 / getTaskView().getNonGridScale();
float recentsMaxScale = getTaskView() == null || getTaskView().getRecentsView() == null
? 1 : 1 / getTaskView().getRecentsView().getMaxScaleForFullScreen();
- float scale = nonGridScale * recentsMaxScale;
+ float scaleX = nonGridScale * recentsMaxScale * (1 / getScaleX());
+ float scaleY = nonGridScale * recentsMaxScale * (1 / getScaleY());
// Center the image in the view.
matrix.setTranslate(centeredDrawableLeft, centeredDrawableTop);
// Apply scale transformation after translation, pivoting around center of view.
- matrix.postScale(scale, scale, viewCenterX, viewCenterY);
+ matrix.postScale(scaleX, scaleY, viewCenterX, viewCenterY);
imageView.setImageMatrix(matrix);
mSplashView = imageView;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ab72f2d..a06e1f8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.widget.Toast.LENGTH_SHORT;
@@ -41,6 +42,7 @@
import android.animation.ObjectAnimator;
import android.annotation.IdRes;
import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
@@ -706,9 +708,12 @@
}
SplitSelectStateController splitSelectStateController =
recentsView.getSplitSelectController();
- if (splitSelectStateController.isSplitSelectActive() &&
- splitSelectStateController.getInitialTaskId() == getTask().key.id) {
- // Prevent taps on the this taskview if it's being animated into split select state
+ // Disable taps for split selection animation unless we have multiple tasks
+ boolean disableTapsForSplitSelect =
+ splitSelectStateController.isSplitSelectActive()
+ && splitSelectStateController.getInitialTaskId() == getTask().key.id
+ && !containsMultipleTasks();
+ if (disableTapsForSplitSelect) {
return false;
}
@@ -718,6 +723,25 @@
return super.dispatchTouchEvent(ev);
}
+ /**
+ * @return taskId that split selection was initiated with,
+ * {@link ActivityTaskManager#INVALID_TASK_ID} if no tasks in this TaskView are part of
+ * split selection
+ */
+ protected int getThisTaskCurrentlyInSplitSelection() {
+ SplitSelectStateController splitSelectController =
+ getRecentsView().getSplitSelectController();
+ int initSplitTaskId = INVALID_TASK_ID;
+ for (TaskIdAttributeContainer container : getTaskIdAttributeContainers()) {
+ int taskId = container.getTask().key.id;
+ if (taskId == splitSelectController.getInitialTaskId()) {
+ initSplitTaskId = taskId;
+ break;
+ }
+ }
+ return initSplitTaskId;
+ }
+
private void onClick(View view) {
if (getTask() == null) {
return;
@@ -747,6 +771,8 @@
/**
* Returns the task index of the last selected child task (0 or 1).
+ * If we contain multiple tasks and this TaskView is used as part of split selection, the
+ * selected child task index will be that of the remaining task.
*/
protected int getLastSelectedChildTaskIndex() {
return 0;
@@ -1084,6 +1110,8 @@
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ // TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead
+ // of a hybrid of both margins and translations
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
mSnapshotView.setLayoutParams(snapshotParams);
@@ -1179,6 +1207,7 @@
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
setColorTint(0, 0);
+ mSnapshotView.resetViewTransforms();
}
public void setStableAlpha(float parentAlpha) {
@@ -1720,10 +1749,12 @@
}
/**
- * Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
- * IconView is unaffected.
+ * Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
+ * IconView is unaffected.
+ *
+ * @param taskId is only used when setting visibility to a non-{@link View#VISIBLE} value
*/
- void setThumbnailVisibility(int visibility) {
+ void setThumbnailVisibility(int visibility, int taskId) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child != mIconView) {
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index eb6d096..9d5b08e 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -2,6 +2,7 @@
import static android.os.Process.myUserHandle;
+import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
@@ -51,10 +52,10 @@
*/
@WorkerThread
public static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds,
- @NonNull LauncherWidgetHolder holder) {
+ @NonNull AppWidgetHost host) {
if (WidgetsModel.GO_DISABLE_WIDGETS) {
Log.e(TAG, "Skipping widget ID remap as widgets not supported");
- holder.deleteHost();
+ host.deleteHost();
return;
}
if (!RestoreDbTask.isPending(context)) {
@@ -63,7 +64,7 @@
Log.e(TAG, "Skipping widget ID remap as DB already in use");
for (int widgetId : newWidgetIds) {
Log.d(TAG, "Deleting widgetId: " + widgetId);
- holder.deleteAppWidgetId(widgetId);
+ host.deleteAppWidgetId(widgetId);
}
return;
}
@@ -100,7 +101,7 @@
try {
if (!cursor.moveToFirst()) {
// The widget no long exists.
- holder.deleteAppWidgetId(newWidgetIds[i]);
+ host.deleteAppWidgetId(newWidgetIds[i]);
}
} finally {
cursor.close();
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 352163e..801b740 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -832,7 +832,7 @@
|| info.hasPromiseIconUi()
|| (info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0
|| (ENABLE_DOWNLOAD_APP_UX_V2.get() && icon != null)) {
- updateProgressBarUi(icon);
+ updateProgressBarUi(info.getProgressLevel() == 100 ? icon : null);
}
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 87ee4f6..d992ee0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -193,7 +193,7 @@
private final int mMinHotseatIconSpacePx;
private final int mMinHotseatQsbWidthPx;
private final int mMaxHotseatIconSpacePx;
- private final int mInlineNavButtonsEndSpacingPx;
+ public final int inlineNavButtonsEndSpacingPx;
// Bottom sheets
public int bottomSheetTopPadding;
@@ -490,7 +490,7 @@
hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
updateHotseatSizes(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
if (areNavButtonsInline && !isPhone) {
- mInlineNavButtonsEndSpacingPx =
+ inlineNavButtonsEndSpacingPx =
res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing);
/*
* 3 nav buttons +
@@ -499,9 +499,9 @@
*/
hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+ 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween)
- + mInlineNavButtonsEndSpacingPx;
+ + inlineNavButtonsEndSpacingPx;
} else {
- mInlineNavButtonsEndSpacingPx = 0;
+ inlineNavButtonsEndSpacingPx = 0;
hotseatBarEndOffset = 0;
}
@@ -662,7 +662,7 @@
}
// The side space with inline buttons should be what is defined in InvariantDeviceProfile
- int sideSpacePx = mInlineNavButtonsEndSpacingPx;
+ int sideSpacePx = inlineNavButtonsEndSpacingPx;
int maxHotseatWidthPx = availableWidthPx - sideSpacePx - hotseatBarEndOffset;
int maxHotseatIconsWidthPx = maxHotseatWidthPx - (isQsbInline ? hotseatQsbWidth : 0);
hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidthPx,
@@ -1320,7 +1320,7 @@
int endSpacing;
// Hotseat aligns to the left with nav buttons
if (hotseatBarEndOffset > 0) {
- startSpacing = mInlineNavButtonsEndSpacingPx;
+ startSpacing = inlineNavButtonsEndSpacingPx;
endSpacing = availableWidthPx - hotseatWidth - startSpacing + hotseatBorderSpace;
} else {
startSpacing = (availableWidthPx - hotseatWidth) / 2;
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 767c3d9..bccb894 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -550,39 +550,42 @@
Log.d(TAG, "loading default workspace");
LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
- AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder);
- if (loader == null) {
- loader = AutoInstallsLayout.get(getContext(), widgetHolder, mOpenHelper);
- }
- if (loader == null) {
- final Partner partner = Partner.get(getContext().getPackageManager());
- if (partner != null) {
- int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT);
- if (workspaceResId != 0) {
- loader = new DefaultLayoutParser(getContext(), widgetHolder,
- mOpenHelper, partner.getResources(), workspaceResId);
+ try {
+ AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder);
+ if (loader == null) {
+ loader = AutoInstallsLayout.get(getContext(), widgetHolder, mOpenHelper);
+ }
+ if (loader == null) {
+ final Partner partner = Partner.get(getContext().getPackageManager());
+ if (partner != null) {
+ int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT);
+ if (workspaceResId != 0) {
+ loader = new DefaultLayoutParser(getContext(), widgetHolder,
+ mOpenHelper, partner.getResources(), workspaceResId);
+ }
}
}
- }
- final boolean usingExternallyProvidedLayout = loader != null;
- if (loader == null) {
- loader = getDefaultLayoutParser(widgetHolder);
- }
+ final boolean usingExternallyProvidedLayout = loader != null;
+ if (loader == null) {
+ loader = getDefaultLayoutParser(widgetHolder);
+ }
- // There might be some partially restored DB items, due to buggy restore logic in
- // previous versions of launcher.
- mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
- // Populate favorites table with initial favorites
- if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
- && usingExternallyProvidedLayout) {
- // Unable to load external layout. Cleanup and load the internal layout.
+ // There might be some partially restored DB items, due to buggy restore logic in
+ // previous versions of launcher.
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
- mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
- getDefaultLayoutParser(widgetHolder));
+ // Populate favorites table with initial favorites
+ if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
+ && usingExternallyProvidedLayout) {
+ // Unable to load external layout. Cleanup and load the internal layout.
+ mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
+ mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
+ getDefaultLayoutParser(widgetHolder));
+ }
+ clearFlagEmptyDbCreated();
+ } finally {
+ widgetHolder.destroy();
}
- clearFlagEmptyDbCreated();
- widgetHolder.destroy();
}
}
@@ -957,8 +960,6 @@
allWidgets = holder.getAppWidgetIds();
} catch (IncompatibleClassChangeError e) {
Log.e(TAG, "getAppWidgetIds not supported", e);
- // Necessary to destroy the holder to free up possible activity context
- holder.destroy();
return;
}
final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 2a452be..3a5ef10 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -21,8 +21,10 @@
import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
+import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
import android.app.backup.BackupManager;
+import android.appwidget.AppWidgetHost;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -49,7 +51,6 @@
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LogConfig;
-import com.android.launcher3.widget.LauncherWidgetHolder;
import java.io.InvalidObjectException;
import java.util.Arrays;
@@ -354,12 +355,11 @@
private void restoreAppWidgetIdsIfExists(Context context) {
LauncherPrefs lp = LauncherPrefs.get(context);
if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
- LauncherWidgetHolder holder = LauncherWidgetHolder.newInstance(context);
+ AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
AppWidgetsRestoredReceiver.restoreAppWidgetIds(context,
IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
- holder);
- holder.destroy();
+ host);
} else {
FileLog.d(TAG, "No app widget ids to restore.");
}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 628aa9a..295baa3 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -635,6 +635,9 @@
primarySnapshot.setTranslationX(0);
}
secondarySnapshot.setTranslationY(spaceAboveSnapshot);
+
+ // Reset unused translations
+ primarySnapshot.setTranslationY(0);
} else {
int deviceHeightWithoutTaskbar = dp.availableHeightPx - dp.taskbarSize;
float scale = (float) totalThumbnailHeight / deviceHeightWithoutTaskbar;
@@ -669,6 +672,10 @@
View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
View.MeasureSpec.EXACTLY));
+ primarySnapshot.setScaleX(1);
+ secondarySnapshot.setScaleX(1);
+ primarySnapshot.setScaleY(1);
+ secondarySnapshot.setScaleY(1);
}
@Override
@@ -699,13 +706,13 @@
: deviceProfile.getInsets().left;
int fullscreenMidpointFromBottom = ((deviceProfile.widthPx
- fullscreenInsetThickness) / 2);
- float midpointFromBottomPct = (float) fullscreenMidpointFromBottom
+ float midpointFromEndPct = (float) fullscreenMidpointFromBottom
/ deviceProfile.widthPx;
float insetPct = (float) fullscreenInsetThickness / deviceProfile.widthPx;
int spaceAboveSnapshots = 0;
int overviewThumbnailAreaThickness = groupedTaskViewWidth - spaceAboveSnapshots;
int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness
- * midpointFromBottomPct);
+ * midpointFromEndPct);
int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
if (deviceProfile.isSeascape()) {
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index bea7517..8e67eb1 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -322,13 +322,6 @@
}
/**
- * Delete the host
- */
- public void deleteHost() {
- mWidgetHost.deleteHost();
- }
-
- /**
* @return The app widget ids
*/
@NonNull