Merge "Remove redundant instances of depth controller." into udc-dev
diff --git a/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml b/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml
deleted file mode 100644
index 2ab6749..0000000
--- a/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="?attr/surfaceHome" />
-</shape>
diff --git a/quickstep/res/drawable/hotseat_icon_home.xml b/quickstep/res/drawable/redesigned_hotseat_icon.xml
similarity index 94%
rename from quickstep/res/drawable/hotseat_icon_home.xml
rename to quickstep/res/drawable/redesigned_hotseat_icon.xml
index 9ef4863..535756d 100644
--- a/quickstep/res/drawable/hotseat_icon_home.xml
+++ b/quickstep/res/drawable/redesigned_hotseat_icon.xml
@@ -16,6 +16,5 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/surfaceHome" />
<corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
</shape>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
index af86ae7..3b484dc 100644
--- a/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -40,28 +40,28 @@
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
index 983c15b..850f6e3 100644
--- a/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
@@ -39,42 +39,42 @@
android:id="@+id/hotseat_search_bar"
android:layout_width="200dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
index b41eb8d..821628a 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
@@ -26,7 +26,7 @@
android:id="@+id/hotseat_search_bar"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true"
app:layout_constraintTop_toTopOf="parent"
@@ -50,35 +50,35 @@
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index 6c4ca2e..7d5505e 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -96,15 +96,6 @@
android:layout_height="match_parent"
android:background="@drawable/gesture_tutorial_ripple" />
- <include
- android:id="@+id/gesture_tutorial_fake_taskbar_view"
- layout="@layout/gesture_tutorial_tablet_mock_taskbar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="@dimen/gesture_tutorial_taskbar_margin_bottom" />
-
<ImageView
android:id="@+id/gesture_tutorial_edge_gesture_video"
android:layout_width="match_parent"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
index e93a0fc..f5145ba 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -39,35 +39,36 @@
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
+ android:id="@+id/hotseat_search_bar"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
index b41eb8d..821628a 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
@@ -26,7 +26,7 @@
android:id="@+id/hotseat_search_bar"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true"
app:layout_constraintTop_toTopOf="parent"
@@ -50,35 +50,35 @@
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
<View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
- android:background="@drawable/hotseat_icon_home"
+ android:background="@drawable/redesigned_hotseat_icon"
android:clipToOutline="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 8cf6837..c2b4d92 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -23,7 +23,7 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"Remover tudo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Tarefa encerrada"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index b1faf88..42e51cd 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1705,6 +1705,7 @@
QuickStepContract.getWindowCornerRadius(mLauncher),
false /* fromPredictiveBack */);
+ TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, false, null);
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
result.setAnimation(pair.second, mLauncher);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 08857b7..8a11b57 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -27,11 +27,13 @@
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
+import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.BorderAnimator;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -43,7 +45,9 @@
*/
public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
- @NonNull private final BorderAnimator mBorderAnimator;
+ @ColorInt private final int mBorderColor;
+
+ @Nullable private BorderAnimator mBorderAnimator;
@Nullable private ImageView mThumbnailView1;
@Nullable private ImageView mThumbnailView2;
@@ -74,29 +78,9 @@
attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);
setWillNotDraw(false);
- Resources resources = context.getResources();
- mBorderAnimator = new BorderAnimator(
- /* borderBoundsBuilder= */ bounds -> bounds.set(0, 0, getWidth(), getHeight()),
- /* borderWidthPx= */ resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_border_width),
- /* borderRadiusPx= */ resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_task_view_radius),
- /* borderColor= */ ta.getColor(
- R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR),
- /* invalidateViewCallback= */ KeyboardQuickSwitchTaskView.this::invalidate,
- /* viewScaleTargetProvider= */ new BorderAnimator.ViewScaleTargetProvider() {
- @NonNull
- @Override
- public View getContainerView() {
- return KeyboardQuickSwitchTaskView.this;
- }
- @NonNull
- @Override
- public View getContentView() {
- return mContent;
- }
- });
+ mBorderColor = ta.getColor(
+ R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR);
ta.recycle();
}
@@ -108,17 +92,34 @@
mIcon1 = findViewById(R.id.icon1);
mIcon2 = findViewById(R.id.icon2);
mContent = findViewById(R.id.content);
+
+ Resources resources = mContext.getResources();
+
+ Preconditions.assertNotNull(mContent);
+ mBorderAnimator = new BorderAnimator(
+ /* borderRadiusPx= */ resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_task_view_radius),
+ /* borderColor= */ mBorderColor,
+ /* borderAnimationParams= */ new BorderAnimator.ScalingParams(
+ /* borderWidthPx= */ resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* boundsBuilder= */ bounds -> bounds.set(
+ 0, 0, getWidth(), getHeight()),
+ /* targetView= */ this,
+ /* contentView= */ mContent));
}
- @NonNull
+ @Nullable
protected Animator getFocusAnimator(boolean focused) {
- return mBorderAnimator.buildAnimator(focused);
+ return mBorderAnimator == null ? null : mBorderAnimator.buildAnimator(focused);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- mBorderAnimator.drawBorder(canvas);
+ if (mBorderAnimator != null) {
+ mBorderAnimator.drawBorder(canvas);
+ }
}
protected void setThumbnails(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 0a83279..040b8f7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -153,6 +153,11 @@
return false;
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick");
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.TWO_TASKBAR_LONG_CLICKS,
+ "TaskbarDragController.startDragOnLongClick",
+ new Throwable());
+ }
BubbleTextView btv = (BubbleTextView) view;
mActivity.onDragStart();
btv.post(() -> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 1ceb653..8e1059b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -54,6 +54,10 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ // Used to defer any UI updates during the SUW unstash animation.
+ private boolean mDeferUpdatesForSUW;
+ private Runnable mDeferredUpdates;
+
public TaskbarModelCallbacks(
TaskbarActivityContext context, TaskbarView container) {
mContext = context;
@@ -194,10 +198,38 @@
}
hotseatItemInfos = mControllers.taskbarRecentAppsController
.updateHotseatItemInfos(hotseatItemInfos);
+
+ if (mDeferUpdatesForSUW) {
+ ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
+ mDeferredUpdates = () -> {
+ updateHotseatItemsAndBackground(finalHotseatItemInfos);
+ };
+ } else {
+ updateHotseatItemsAndBackground(hotseatItemInfos);
+ }
+ }
+
+ private void updateHotseatItemsAndBackground(ItemInfo[] hotseatItemInfos) {
mContainer.updateHotseatItems(hotseatItemInfos);
mControllers.taskbarViewController.updateIconsBackground();
}
+ /**
+ * This is used to defer UI updates after SUW builds the unstash animation.
+ * @param defer if true, defers updates to the UI
+ * if false, posts updates (if any) to the UI
+ */
+ public void setDeferUpdatesForSUW(boolean defer) {
+ mDeferUpdatesForSUW = defer;
+
+ if (!mDeferUpdatesForSUW) {
+ if (mDeferredUpdates != null) {
+ mContainer.post(mDeferredUpdates);
+ mDeferredUpdates = null;
+ }
+ }
+ }
+
@Override
public void onRunningTasksChanged() {
updateRunningApps();
@@ -232,5 +264,7 @@
pw.println(
String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size()));
}
+ pw.println(String.format("%s\tmDeferUpdatesForSUW=%b", prefix, mDeferUpdatesForSUW));
+ pw.println(String.format("%s\tupdates pending=%b", prefix, (mDeferredUpdates != null)));
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 6f82c7d..00e14ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -585,10 +585,14 @@
* actually be used since this animation tracks a swipe progress.
*/
protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
+ // Defer any UI updates now to avoid the UI becoming stale when the animation plays.
+ mControllers.taskbarViewController.setDeferUpdatesForSUW(true);
createAnimToIsStashed(
/* isStashed= */ false,
placeholderDuration,
TRANSITION_UNSTASH_SUW_MANUAL);
+ animation.addListener(AnimatorListeners.forEndCallback(
+ () -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false)));
animation.play(mAnimator);
}
@@ -804,7 +808,7 @@
}
mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
- EMPHASIZED);
+ EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL);
play(skippable, mControllers.stashedHandleViewController
.createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 7429185..4abd995 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
+import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -286,7 +287,7 @@
}
private ValueAnimator createRevealAnimForView(View view, boolean isStashed, float newWidth,
- boolean isQsb) {
+ boolean isQsb, boolean dispatchOnAnimationStart) {
Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
int centerY = viewBounds.centerY();
int halfHandleHeight = mStashedHandleHeight / 2;
@@ -318,8 +319,24 @@
: 0f;
float stashedRadius = stashedRect.height() / 2f;
- return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
+ ValueAnimator reveal = new RoundedRectRevealOutlineProvider(radius,
+ stashedRadius, viewBounds, stashedRect)
.createRevealAnimator(view, !isStashed, 0);
+ // SUW animation does not dispatch animation start until *after* the animation is complete.
+ // In order to work properly, the reveal animation start needs to be called immediately.
+ if (dispatchOnAnimationStart) {
+ for (Animator.AnimatorListener listener : reveal.getListeners()) {
+ listener.onAnimationStart(reveal);
+ }
+ }
+ return reveal;
+ }
+
+ /**
+ * Defers any updates to the UI for the setup wizard animation.
+ */
+ public void setDeferUpdatesForSUW(boolean defer) {
+ mModelCallbacks.setDeferUpdatesForSUW(defer);
}
/**
@@ -332,7 +349,7 @@
* @param interpolator The interpolator to use for all animations.
*/
public void addRevealAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- Interpolator interpolator) {
+ Interpolator interpolator, boolean dispatchOnAnimationStart) {
AnimatorSet reveal = new AnimatorSet();
Rect stashedBounds = new Rect();
@@ -349,8 +366,8 @@
boolean isQsb = child == mTaskbarView.getQsb();
// Crop the icons to/from the nav handle shape.
- reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb)
- .setDuration(duration));
+ reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb,
+ dispatchOnAnimationStart).setDuration(duration));
// Translate the icons to/from their locations as the "nav handle."
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 5902912..a642693 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -27,7 +27,6 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarDragController;
-import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
@@ -45,8 +44,6 @@
private final TaskbarDragController mDragController;
private final TaskbarOverlayDragLayer mDragLayer;
- // We automatically stash taskbar when All Apps is opened in gesture navigation mode.
- private final boolean mWillTaskbarBeVisuallyStashed;
private final int mStashedTaskbarHeight;
private final TaskbarUIController mUiController;
@@ -60,18 +57,11 @@
mDragController = new TaskbarDragController(this);
mDragController.init(controllers);
mDragLayer = new TaskbarOverlayDragLayer(this);
-
- TaskbarStashController taskbarStashController = controllers.taskbarStashController;
- mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing();
- mStashedTaskbarHeight = taskbarStashController.getStashedHeight();
+ mStashedTaskbarHeight = controllers.taskbarStashController.getStashedHeight();
mUiController = controllers.uiController;
}
- boolean willTaskbarBeVisuallyStashed() {
- return mWillTaskbarBeVisuallyStashed;
- }
-
int getStashedTaskbarHeight() {
return mStashedTaskbarHeight;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index b4ec682..add7279 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -32,6 +32,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
@@ -185,7 +186,7 @@
* 2) Sets tappableInsets bottom inset to 0.
*/
private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
- if (!mActivity.willTaskbarBeVisuallyStashed()) {
+ if (!DisplayController.isTransientTaskbar(mActivity)) {
return oldInsets;
}
WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 79a301a..95c2326 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1282,7 +1282,8 @@
getActivityLaunchOptions(taskView, null).options));
return;
}
- mSplitSelectStateController.launchTasks(
+ mSplitSelectStateController.launchExistingSplitPair(
+ null /* launchingTaskView */,
groupTask.task1.key.id,
groupTask.task2.key.id,
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index db38cb6..0012d47 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -131,6 +131,11 @@
}
@Override
+ protected int getHotseatIconColor() {
+ return getExitingAppColor();
+ }
+
+ @Override
public void onBackGestureAttempted(BackGestureResult result) {
if (isGestureCompleted()) {
return;
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index d031677..593e6d9 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -134,7 +134,7 @@
}
@Override
- protected int getExitingAppColor() {
+ protected int getHotseatIconColor() {
return mTutorialFragment.mRootView.mColorOnSurfaceOverview;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 06d957a..36655d2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -29,6 +29,7 @@
import android.annotation.RawRes;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -107,7 +108,7 @@
@Nullable View mHotseatIconView;
final ClipIconView mFakeIconView;
final FrameLayout mFakeTaskView;
- final AnimatedTaskbarView mFakeTaskbarView;
+ @Nullable final AnimatedTaskbarView mFakeTaskbarView;
final AnimatedTaskView mFakePreviousTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
@@ -149,7 +150,8 @@
mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
- mFakeTaskbarView = rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
+ mFakeTaskbarView = ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+ ? null : rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
mFakePreviousTaskView =
rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@@ -269,12 +271,19 @@
protected abstract int getSwipeActionColor();
@ColorInt
- protected abstract int getExitingAppColor();
+ protected int getExitingAppColor() {
+ return Color.TRANSPARENT;
+ }
+
+ @ColorInt
+ protected int getHotseatIconColor() {
+ return Color.TRANSPARENT;
+ }
@DrawableRes
public int getMockAppIconResId() {
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.drawable.redesigned_default_sandbox_app_icon
+ ? R.drawable.redesigned_hotseat_icon
: R.drawable.default_sandbox_app_icon;
}
@@ -463,7 +472,7 @@
mFakeTaskView.removeCallbacks(mFakeTaskViewCallback);
mFakeTaskViewCallback = null;
}
- if (mFakeTaskbarViewCallback != null) {
+ if (mFakeTaskbarViewCallback != null && mFakeTaskbarView != null) {
mFakeTaskbarView.removeCallbacks(mFakeTaskbarViewCallback);
mFakeTaskbarViewCallback = null;
}
@@ -621,7 +630,7 @@
}
void hideFakeTaskbar(boolean animateToHotseat) {
- if (!mTutorialFragment.isLargeScreen()) {
+ if (!mTutorialFragment.isLargeScreen() || mFakeTaskbarView == null) {
return;
}
if (mFakeTaskbarViewCallback != null) {
@@ -635,7 +644,7 @@
}
void showFakeTaskbar(boolean animateFromHotseat) {
- if (!mTutorialFragment.isLargeScreen()) {
+ if (!mTutorialFragment.isLargeScreen() || mFakeTaskbarView == null) {
return;
}
if (mFakeTaskbarViewCallback != null) {
@@ -670,6 +679,11 @@
}
}
+ private void updateHotseatChildViewColor(@Nullable View child) {
+ if (child == null) return;
+ child.getBackground().setTint(getHotseatIconColor());
+ }
+
private void updateDrawables() {
if (mContext != null) {
mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable(
@@ -689,6 +703,12 @@
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mExitingAppView.setBackgroundColor(getExitingAppColor());
+ updateHotseatChildViewColor(mFakeIconView);
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
}
}
}
@@ -712,8 +732,10 @@
? R.dimen.gesture_tutorial_tablet_feedback_margin_top
: R.dimen.gesture_tutorial_feedback_margin_top);
- mFakeTaskbarView.setVisibility((mTutorialFragment.isLargeScreen()
- && !ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) ? View.VISIBLE : GONE);
+ if (mFakeTaskbarView != null) {
+ mFakeTaskbarView.setVisibility(
+ mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
+ }
RelativeLayout.LayoutParams hotseatLayoutParams =
(RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.java b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
index c43fb27..011d45c 100644
--- a/quickstep/src/com/android/quickstep/util/BorderAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
@@ -20,6 +20,7 @@
import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
@@ -37,8 +38,8 @@
* <p>
* To use this class:
* 1. Create an instance in the target view. NOTE: The border will animate outwards from the
- * provided border bounds. If the border will not be visible outside of those bounds, then a
- * {@link ViewScaleTargetProvider} must be provided in the constructor.
+ * provided border bounds. See {@link SimpleParams} and {@link ScalingParams} to determine
+ * which would be best for your target view.
* 2. Override the target view's {@link android.view.View#draw(Canvas)} method and call
* {@link BorderAnimator#drawBorder(Canvas)} after {@code super.draw(canvas)}.
* 3. Call {@link BorderAnimator#buildAnimator(boolean)} and start the animation or call
@@ -46,7 +47,7 @@
*/
public final class BorderAnimator {
- public static final int DEFAULT_BORDER_COLOR = 0xffffffff;
+ public static final int DEFAULT_BORDER_COLOR = Color.WHITE;
private static final long DEFAULT_APPEARANCE_ANIMATION_DURATION_MS = 300;
private static final long DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS = 133;
@@ -54,68 +55,44 @@
@NonNull private final AnimatedFloat mBorderAnimationProgress = new AnimatedFloat(
this::updateOutline);
- @NonNull private final Rect mBorderBounds = new Rect();
- @NonNull private final BorderBoundsBuilder mBorderBoundsBuilder;
- @Px private final int mBorderWidthPx;
@Px private final int mBorderRadiusPx;
- @NonNull private final Runnable mInvalidateViewCallback;
- @Nullable private final ViewScaleTargetProvider mViewScaleTargetProvider;
+ @NonNull private final BorderAnimationParams mBorderAnimationParams;
private final long mAppearanceDurationMs;
private final long mDisappearanceDurationMs;
@NonNull private final Interpolator mInterpolator;
@NonNull private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private float mAlignmentAdjustment;
-
@Nullable private Animator mRunningBorderAnimation;
public BorderAnimator(
- @NonNull BorderBoundsBuilder borderBoundsBuilder,
- int borderWidthPx,
- int borderRadiusPx,
+ @Px int borderRadiusPx,
@ColorInt int borderColor,
- @NonNull Runnable invalidateViewCallback) {
- this(borderBoundsBuilder,
- borderWidthPx,
- borderRadiusPx,
+ @NonNull BorderAnimationParams borderAnimationParams) {
+ this(borderRadiusPx,
borderColor,
- invalidateViewCallback,
- /* viewScaleTargetProvider= */ null);
- }
-
- public BorderAnimator(
- @NonNull BorderBoundsBuilder borderBoundsBuilder,
- int borderWidthPx,
- int borderRadiusPx,
- @ColorInt int borderColor,
- @NonNull Runnable invalidateViewCallback,
- @Nullable ViewScaleTargetProvider viewScaleTargetProvider) {
- this(borderBoundsBuilder,
- borderWidthPx,
- borderRadiusPx,
- borderColor,
- invalidateViewCallback,
- viewScaleTargetProvider,
+ borderAnimationParams,
DEFAULT_APPEARANCE_ANIMATION_DURATION_MS,
DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS,
DEFAULT_INTERPOLATOR);
}
+ /**
+ * @param borderRadiusPx the radius of the border's corners, in pixels
+ * @param borderColor the border's color
+ * @param borderAnimationParams params for handling different target view layout situation.
+ * @param appearanceDurationMs appearance animation duration, in milliseconds
+ * @param disappearanceDurationMs disappearance animation duration, in milliseconds
+ * @param interpolator animation interpolator
+ */
public BorderAnimator(
- @NonNull BorderBoundsBuilder borderBoundsBuilder,
- int borderWidthPx,
- int borderRadiusPx,
+ @Px int borderRadiusPx,
@ColorInt int borderColor,
- @NonNull Runnable invalidateViewCallback,
- @Nullable ViewScaleTargetProvider viewScaleTargetProvider,
+ @NonNull BorderAnimationParams borderAnimationParams,
long appearanceDurationMs,
long disappearanceDurationMs,
@NonNull Interpolator interpolator) {
- mBorderBoundsBuilder = borderBoundsBuilder;
- mBorderWidthPx = borderWidthPx;
mBorderRadiusPx = borderRadiusPx;
- mInvalidateViewCallback = invalidateViewCallback;
- mViewScaleTargetProvider = viewScaleTargetProvider;
+ mBorderAnimationParams = borderAnimationParams;
mAppearanceDurationMs = appearanceDurationMs;
mDisappearanceDurationMs = disappearanceDurationMs;
mInterpolator = interpolator;
@@ -128,15 +105,11 @@
private void updateOutline() {
float interpolatedProgress = mInterpolator.getInterpolation(
mBorderAnimationProgress.value);
- float borderWidth = mBorderWidthPx * interpolatedProgress;
- // Outset the border by half the width to create an outwards-growth animation
- mAlignmentAdjustment = (-borderWidth / 2f)
- // Inset the border if we are scaling the container up
- + (mViewScaleTargetProvider == null ? 0 : mBorderWidthPx);
+ mBorderAnimationParams.setProgress(interpolatedProgress);
mBorderPaint.setAlpha(Math.round(255 * interpolatedProgress));
- mBorderPaint.setStrokeWidth(borderWidth);
- mInvalidateViewCallback.run();
+ mBorderPaint.setStrokeWidth(mBorderAnimationParams.getBorderWidth());
+ mBorderAnimationParams.mTargetView.invalidate();
}
/**
@@ -146,16 +119,14 @@
* calling super.
*/
public void drawBorder(Canvas canvas) {
- // Increase the radius if we are scaling the container up
- float radiusAdjustment = mViewScaleTargetProvider == null
- ? -mAlignmentAdjustment : mAlignmentAdjustment;
+ float alignmentAdjustment = mBorderAnimationParams.getAlignmentAdjustment();
canvas.drawRoundRect(
- /* left= */ mBorderBounds.left + mAlignmentAdjustment,
- /* top= */ mBorderBounds.top + mAlignmentAdjustment,
- /* right= */ mBorderBounds.right - mAlignmentAdjustment,
- /* bottom= */ mBorderBounds.bottom - mAlignmentAdjustment,
- /* rx= */ mBorderRadiusPx + radiusAdjustment,
- /* ry= */ mBorderRadiusPx + radiusAdjustment,
+ /* left= */ mBorderAnimationParams.mBorderBounds.left + alignmentAdjustment,
+ /* top= */ mBorderAnimationParams.mBorderBounds.top + alignmentAdjustment,
+ /* right= */ mBorderAnimationParams.mBorderBounds.right - alignmentAdjustment,
+ /* bottom= */ mBorderAnimationParams.mBorderBounds.bottom - alignmentAdjustment,
+ /* rx= */ mBorderRadiusPx + mBorderAnimationParams.getRadiusAdjustment(),
+ /* ry= */ mBorderRadiusPx + mBorderAnimationParams.getRadiusAdjustment(),
/* paint= */ mBorderPaint);
}
@@ -164,7 +135,6 @@
*/
@NonNull
public Animator buildAnimator(boolean isAppearing) {
- mBorderBoundsBuilder.updateBorderBounds(mBorderBounds);
mRunningBorderAnimation = mBorderAnimationProgress.animateToValue(isAppearing ? 1f : 0f);
mRunningBorderAnimation.setDuration(
isAppearing ? mAppearanceDurationMs : mDisappearanceDurationMs);
@@ -172,7 +142,7 @@
mRunningBorderAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- setViewScales();
+ mBorderAnimationParams.onShowBorder();
}
});
mRunningBorderAnimation.addListener(
@@ -181,7 +151,7 @@
if (isAppearing) {
return;
}
- resetViewScales();
+ mBorderAnimationParams.onHideBorder();
}));
return mRunningBorderAnimation;
@@ -196,56 +166,15 @@
if (mRunningBorderAnimation != null) {
mRunningBorderAnimation.end();
}
- mBorderBoundsBuilder.updateBorderBounds(mBorderBounds);
if (visible) {
- setViewScales();
+ mBorderAnimationParams.onShowBorder();
}
mBorderAnimationProgress.updateValue(visible ? 1f : 0f);
if (!visible) {
- resetViewScales();
+ mBorderAnimationParams.onHideBorder();
}
}
- private void setViewScales() {
- if (mViewScaleTargetProvider == null) {
- return;
- }
- View container = mViewScaleTargetProvider.getContainerView();
- float width = container.getWidth();
- float height = container.getHeight();
- // scale up just enough to make room for the border
- float scaleX = 1f + ((2 * mBorderWidthPx) / width);
- float scaleY = 1f + ((2 * mBorderWidthPx) / height);
-
- container.setPivotX(width / 2);
- container.setPivotY(height / 2);
- container.setScaleX(scaleX);
- container.setScaleY(scaleY);
-
- View contentView = mViewScaleTargetProvider.getContentView();
- contentView.setPivotX(contentView.getWidth() / 2f);
- contentView.setPivotY(contentView.getHeight() / 2f);
- contentView.setScaleX(1f / scaleX);
- contentView.setScaleY(1f / scaleY);
- }
-
- private void resetViewScales() {
- if (mViewScaleTargetProvider == null) {
- return;
- }
- View container = mViewScaleTargetProvider.getContainerView();
- container.setPivotX(container.getWidth());
- container.setPivotY(container.getHeight());
- container.setScaleX(1f);
- container.setScaleY(1f);
-
- View contentView = mViewScaleTargetProvider.getContentView();
- contentView.setPivotX(contentView.getWidth() / 2f);
- contentView.setPivotY(contentView.getHeight() / 2f);
- contentView.setScaleX(1f);
- contentView.setScaleY(1f);
- }
-
/**
* Callback to update the border bounds when building this animation.
*/
@@ -258,23 +187,166 @@
}
/**
- * Provider for scaling target views for the beginning and end of this animation.
+ * Params for handling different target view layout situation.
*/
- public interface ViewScaleTargetProvider {
+ private abstract static class BorderAnimationParams {
+
+ @NonNull private final Rect mBorderBounds = new Rect();
+ @NonNull private final BorderBoundsBuilder mBoundsBuilder;
+
+ @NonNull final View mTargetView;
+ @Px final int mBorderWidthPx;
+
+ private float mAnimationProgress = 0f;
+ @Nullable private View.OnLayoutChangeListener mLayoutChangeListener;
/**
- * Returns the content view's container. This view will be scaled up to make room for the
- * border.
+ * @param borderWidthPx the width of the border, in pixels
+ * @param boundsBuilder callback to update the border bounds
+ * @param targetView the view that will be drawing the border
*/
- @NonNull
- View getContainerView();
+ private BorderAnimationParams(
+ @Px int borderWidthPx,
+ @NonNull BorderBoundsBuilder boundsBuilder,
+ @NonNull View targetView) {
+ mBorderWidthPx = borderWidthPx;
+ mBoundsBuilder = boundsBuilder;
+ mTargetView = targetView;
+ }
+
+ private void setProgress(float progress) {
+ mAnimationProgress = progress;
+ }
+
+ private float getBorderWidth() {
+ return mBorderWidthPx * mAnimationProgress;
+ }
+
+ float getAlignmentAdjustment() {
+ // Outset the border by half the width to create an outwards-growth animation
+ return (-getBorderWidth() / 2f) + getAlignmentAdjustmentInset();
+ }
+
+
+ void onShowBorder() {
+ if (mLayoutChangeListener == null) {
+ mLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ onShowBorder();
+ mTargetView.invalidate();
+ };
+ mTargetView.addOnLayoutChangeListener(mLayoutChangeListener);
+ }
+ mBoundsBuilder.updateBorderBounds(mBorderBounds);
+ }
+
+ void onHideBorder() {
+ if (mLayoutChangeListener != null) {
+ mTargetView.removeOnLayoutChangeListener(mLayoutChangeListener);
+ mLayoutChangeListener = null;
+ }
+ }
+
+ abstract int getAlignmentAdjustmentInset();
+
+ abstract float getRadiusAdjustment();
+ }
+
+ /**
+ * Use an instance of this {@link BorderAnimationParams} if the border can be drawn outside the
+ * target view's bounds without any additional logic.
+ */
+ public static final class SimpleParams extends BorderAnimationParams {
+
+ public SimpleParams(
+ @Px int borderWidthPx,
+ @NonNull BorderBoundsBuilder boundsBuilder,
+ @NonNull View targetView) {
+ super(borderWidthPx, boundsBuilder, targetView);
+ }
+
+ @Override
+ int getAlignmentAdjustmentInset() {
+ return 0;
+ }
+
+ @Override
+ float getRadiusAdjustment() {
+ return -getAlignmentAdjustment();
+ }
+ }
+
+ /**
+ * Use an instance of this {@link BorderAnimationParams} if the border would other be clipped by
+ * the target view's bound.
+ * <p>
+ * Note: using these params will set the scales and pivots of the
+ * container and content views, however will only reset the scales back to 1.
+ */
+ public static final class ScalingParams extends BorderAnimationParams {
+
+ @NonNull private final View mContentView;
/**
- * Returns the content view. This view will be scaled down reciprocally to the container's
- * up-scaling to maintain its original size. This should be the view containing all of the
- * content being surrounded by the border.
+ * @param targetView the view that will be drawing the border. this view will be scaled up
+ * to make room for the border
+ * @param contentView the view around which the border will be drawn. this view will be
+ * scaled down reciprocally to keep its original size and location.
*/
- @NonNull
- View getContentView();
+ public ScalingParams(
+ @Px int borderWidthPx,
+ @NonNull BorderBoundsBuilder boundsBuilder,
+ @NonNull View targetView,
+ @NonNull View contentView) {
+ super(borderWidthPx, boundsBuilder, targetView);
+ mContentView = contentView;
+ }
+
+ @Override
+ void onShowBorder() {
+ super.onShowBorder();
+ float width = mTargetView.getWidth();
+ float height = mTargetView.getHeight();
+ // Scale up just enough to make room for the border. Fail fast and fix the scaling
+ // onLayout.
+ float scaleX = width == 0 ? 1f : 1f + ((2 * mBorderWidthPx) / width);
+ float scaleY = height == 0 ? 1f : 1f + ((2 * mBorderWidthPx) / height);
+
+ mTargetView.setPivotX(width / 2);
+ mTargetView.setPivotY(height / 2);
+ mTargetView.setScaleX(scaleX);
+ mTargetView.setScaleY(scaleY);
+
+ mContentView.setPivotX(mContentView.getWidth() / 2f);
+ mContentView.setPivotY(mContentView.getHeight() / 2f);
+ mContentView.setScaleX(1f / scaleX);
+ mContentView.setScaleY(1f / scaleY);
+ }
+
+ @Override
+ void onHideBorder() {
+ super.onHideBorder();
+ mTargetView.setPivotX(mTargetView.getWidth());
+ mTargetView.setPivotY(mTargetView.getHeight());
+ mTargetView.setScaleX(1f);
+ mTargetView.setScaleY(1f);
+
+ mContentView.setPivotX(mContentView.getWidth() / 2f);
+ mContentView.setPivotY(mContentView.getHeight() / 2f);
+ mContentView.setScaleX(1f);
+ mContentView.setScaleY(1f);
+ }
+
+ @Override
+ int getAlignmentAdjustmentInset() {
+ // Inset the border since we are scaling the container up
+ return mBorderWidthPx;
+ }
+
+ @Override
+ float getRadiusAdjustment() {
+ // Increase the radius since we are scaling the container up
+ return getAlignmentAdjustment();
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index da81410..ee51af7 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -298,36 +298,6 @@
}
/**
- * To be called when we want to launch split pairs from an existing GroupedTaskView.
- */
- public void launchTasks(GroupedTaskView groupedTaskView, Consumer<Boolean> callback,
- boolean freezeTaskList) {
- mLaunchingTaskView = groupedTaskView;
- TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
- groupedTaskView.getTaskIdAttributeContainers();
- launchTasks(taskIdAttributeContainers[0].getTask().key.id,
- taskIdAttributeContainers[1].getTask().key.id,
- taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList,
- groupedTaskView.getSplitRatio());
- }
-
- /**
- * To be called when we want to launch split pairs from Overview when split is initiated from
- * Overview.
- */
- public void launchTasks(int taskId1, int taskId2, @StagePosition int stagePosition,
- Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
- if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
- mSplitSelectDataHolder.setInitialTaskSelect(null /*intent*/,
- stagePosition, null /*itemInfo*/, null /*splitEvent*/,
- taskId1);
- mSplitSelectDataHolder.setSecondTask(taskId2);
- }
- launchTasks(taskId1, null /* intent1 */, taskId2, null /* intent2 */, stagePosition,
- callback, freezeTaskList, splitRatio, null);
- }
-
- /**
* To be called when we want to launch split pairs from Overview. Split can be initiated from
* either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
* fill in intent with a taskId2 are set.
@@ -510,6 +480,47 @@
}
}
+ /**
+ * Used to launch split screen from a split pair that already exists (usually accessible through
+ * Overview). This is different than
+ * {@link #launchTasks(int, Intent, int, Intent, int, Consumer, boolean, float, InstanceId)} in
+ * that this only launches split screen that are existing tasks. This doesn't determine which
+ * API should be used (i.e. launching split with existing tasks vs intents vs shortcuts, etc).
+ *
+ * <p/>
+ * NOTE: This is not to be used to launch AppPairs.
+ */
+ public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
+ int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
+ Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+ mLaunchingTaskView = groupedTaskView;
+ final ActivityOptions options1 = ActivityOptions.makeBasic();
+ if (freezeTaskList) {
+ options1.setFreezeRecentTasksReordering();
+ }
+ Bundle optionsBundle = options1.toBundle();
+
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ final RemoteSplitLaunchTransitionRunner animationRunner =
+ new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
+ final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
+ ActivityThread.currentActivityThread().getApplicationThread(),
+ "LaunchSplitPair");
+ mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
+ null /* options2 */, stagePosition, splitRatio,
+ remoteTransition, null /*shellInstanceId*/);
+ } else {
+ final RemoteSplitLaunchAnimationRunner animationRunner =
+ new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ animationRunner, 300, 150,
+ ActivityThread.currentActivityThread().getApplicationThread());
+ mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
+ secondTaskId, null /* options2 */, stagePosition,
+ splitRatio, adapter, null /*shellInstanceId*/);
+ }
+ }
+
private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
int taskId, @StagePosition int stagePosition, float splitRatio,
RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index c6c84bd..c91b183 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -223,13 +223,11 @@
// Callbacks run from remote animation when recents animation not currently running
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Enter form GroupedTaskView");
- recentsView.getSplitSelectController().launchTasks(this /*groupedTaskView*/,
- success -> {
- endCallback.executeAllAndDestroy();
- InteractionJankMonitorWrapper.end(
- InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
- },
- false /* freezeTaskList */);
+ launchTask(success -> {
+ endCallback.executeAllAndDestroy();
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+ }, false /* freezeTaskList */);
// Callbacks get run from recentsView for case when recents animation already running
recentsView.addSideTaskLaunchCallback(endCallback);
@@ -238,9 +236,9 @@
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- getRecentsView().getSplitSelectController().launchTasks(mTask.key.id, mSecondaryTask.key.id,
- SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, callback, isQuickswitch,
- getSplitRatio());
+ getRecentsView().getSplitSelectController().launchExistingSplitPair(this, mTask.key.id,
+ mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+ callback, isQuickswitch, getSplitRatio());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index c47c946..6e7b6dc 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -445,13 +445,14 @@
mBorderAnimator = !keyboardFocusHighlightEnabled
? null
: new BorderAnimator(
- /* borderBoundsBuilder= */ this::updateBorderBounds,
- /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_border_width),
/* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
/* borderColor= */ ta.getColor(
R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR),
- /* invalidateViewCallback= */ TaskView.this::invalidate);
+ /* borderAnimationParams= */ new BorderAnimator.SimpleParams(
+ /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* boundsBuilder= */ this::updateBorderBounds,
+ /* targetView= */ this));
ta.recycle();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 77c76d9..88cac97 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -428,6 +428,55 @@
}
@Test
+ @PortraitLandscape
+ public void testOverviewDeadzones() throws Exception {
+ startTestAppsWithCheck();
+
+ Overview overview = mLauncher.goHome().switchToOverview();
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+ executeOnLauncher(
+ launcher -> assertTrue("Should have at least 3 tasks",
+ getTaskCount(launcher) >= 3));
+
+ // It should not dismiss overview when tapping between tasks
+ overview.touchBetweenTasks();
+ overview = mLauncher.getOverview();
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+
+ // Dismiss when tapping to the right of the focused task
+ overview.touchOutsideFirstTask();
+ assertTrue("Launcher internal state should be Home",
+ isInState(() -> LauncherState.NORMAL));
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testTaskbarDeadzonesForTablet() throws Exception {
+ assumeTrue(mLauncher.isTablet());
+
+ startTestAppsWithCheck();
+
+ Overview overview = mLauncher.goHome().switchToOverview();
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+ executeOnLauncher(
+ launcher -> assertTrue("Should have at least 3 tasks",
+ getTaskCount(launcher) >= 3));
+
+ // On persistent taskbar, it should not dismiss when tapping the taskbar
+ overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+
+ // On persistent taskbar, it should not dismiss when tapping the taskbar
+ overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+ }
+
+ @Test
@ScreenRecord // b/242163205
public void testDisableRotationCheckForPhone() throws Exception {
assumeFalse(mLauncher.isTablet());
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 9ec346a..47bf9e7 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -58,6 +58,7 @@
<com.android.launcher3.views.RecyclerViewFastScroller
android:id="@+id/fast_scroller"
android:layout_width="@dimen/fastscroll_width"
+ android:elevation="1dp"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 94f707a..069d4bc 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -48,7 +48,6 @@
android:layout_height="wrap_content"
android:layout_below="@id/collapse_handle"
android:paddingBottom="0dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToOutline="true"
android:orientation="vertical">
@@ -67,6 +66,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0.1dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:background="?attr/widgetPickerPrimarySurfaceColor"
android:paddingBottom="8dp"
launcher:layout_sticky="true">
@@ -78,6 +78,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:background="@drawable/widgets_surface_background"
android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
android:visibility="gone" />
@@ -89,6 +90,7 @@
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingVertical="8dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:background="?attr/widgetPickerPrimarySurfaceColor"
style="@style/TextHeadline"
launcher:layout_sticky="true">
diff --git a/res/layout/widgets_two_pane_sheet_paged_view.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
index 2e05d48..442957a 100644
--- a/res/layout/widgets_two_pane_sheet_paged_view.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -13,14 +13,14 @@
limitations under the License.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/widgets_two_pane_sheet_paged_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:layout_gravity="start"
android:layout_alignParentStart="true">
<com.android.launcher3.widget.picker.WidgetPagedView
@@ -29,7 +29,6 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
launcher:pageIndicator="@+id/tabs" >
<com.android.launcher3.widget.picker.WidgetsRecyclerView
@@ -62,7 +61,6 @@
android:clipToPadding="false"
android:elevation="0.1dp"
android:paddingBottom="8dp"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
launcher:layout_sticky="true">
<include layout="@layout/widgets_search_bar" />
@@ -73,7 +71,6 @@
android:layout_height="match_parent"
android:id="@+id/suggestions_header"
android:layout_marginTop="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:orientation="horizontal"
android:background="?attr/widgetPickerPrimarySurfaceColor"
launcher:layout_sticky="true">
@@ -86,7 +83,6 @@
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingVertical="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:background="?attr/widgetPickerPrimarySurfaceColor"
style="@style/TextHeadline"
launcher:layout_sticky="true">
diff --git a/res/layout/widgets_two_pane_sheet_recyclerview.xml b/res/layout/widgets_two_pane_sheet_recyclerview.xml
index f8d72e8..c9c855c 100644
--- a/res/layout/widgets_two_pane_sheet_recyclerview.xml
+++ b/res/layout/widgets_two_pane_sheet_recyclerview.xml
@@ -13,8 +13,7 @@
limitations under the License.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/widgets_two_pane_sheet_recyclerview"
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 3dd8627..ec874b9 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -20,7 +20,6 @@
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.IntArray;
@@ -77,16 +76,8 @@
+ "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
+ ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
- try {
- IntArray result = LauncherDbUtils.queryIntArray(false, controller.getDb(),
- Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
- Favorites.APPWIDGET_ID + "!=" + LauncherAppWidgetInfo.NO_ID, null, null);
- // TODO(b/234700507): Remove the logs after the bug is fixed
- Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
- + result.toConcatString());
- } catch (Exception ex) {
- Log.e(TAG, "Getting widget ids from the database failed", ex);
- }
+ // TODO(b/234700507): Remove the logs after the bug is fixed
+ logDatabaseWidgetInfo(controller);
for (int i = 0; i < oldWidgetIds.length; i++) {
Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
@@ -104,9 +95,13 @@
// recreate the widget during loading with the correct host provider.
long mainProfileId = UserCache.INSTANCE.get(context)
.getSerialNumberForUser(myUserHandle());
+ long controllerProfileId = controller.getSerialNumberForUser(myUserHandle());
String oldWidgetId = Integer.toString(oldWidgetIds[i]);
final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
- final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) };
+ String profileId = Long.toString(mainProfileId);
+ final String[] args = new String[] { oldWidgetId, profileId };
+ Log.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
+ + " with controller profile ID=" + controllerProfileId);
int result = new ContentWriter(context,
new ContentWriter.CommitParams(controller, where, args))
.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
@@ -135,4 +130,48 @@
app.getModel().forceReload();
}
}
+
+ private static void logDatabaseWidgetInfo(ModelDbController controller) {
+ try (Cursor cursor = controller.getDb().query(Favorites.TABLE_NAME,
+ new String[]{Favorites.APPWIDGET_ID, Favorites.RESTORED, Favorites.PROFILE_ID},
+ Favorites.APPWIDGET_ID + "!=" + LauncherAppWidgetInfo.NO_ID, null,
+ null, null, null)) {
+ IntArray widgetIdList = new IntArray();
+ IntArray widgetRestoreList = new IntArray();
+ IntArray widgetProfileIdList = new IntArray();
+
+ if (cursor.moveToFirst()) {
+ final int widgetIdColumnIndex = cursor.getColumnIndex(Favorites.APPWIDGET_ID);
+ final int widgetRestoredColumnIndex = cursor.getColumnIndex(Favorites.RESTORED);
+ final int widgetProfileIdIndex = cursor.getColumnIndex(Favorites.PROFILE_ID);
+ while (!cursor.isAfterLast()) {
+ int widgetId = cursor.getInt(widgetIdColumnIndex);
+ int widgetRestoredFlag = cursor.getInt(widgetRestoredColumnIndex);
+ int widgetProfileId = cursor.getInt(widgetProfileIdIndex);
+
+ widgetIdList.add(widgetId);
+ widgetRestoreList.add(widgetRestoredFlag);
+ widgetProfileIdList.add(widgetProfileId);
+ cursor.moveToNext();
+ }
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ for (int i = 0; i < widgetIdList.size(); i++) {
+ builder.append("[")
+ .append(widgetIdList.get(i))
+ .append(", ")
+ .append(widgetRestoreList.get(i))
+ .append(", ")
+ .append(widgetProfileIdList.get(i))
+ .append("]");
+ }
+ builder.append("]");
+ Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
+ + builder.toString());
+ } catch (Exception ex) {
+ Log.e(TAG, "Getting widget ids from the database failed", ex);
+ }
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 26a1886..36e5e1b 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -31,6 +31,8 @@
import android.view.View;
import android.view.ViewDebug;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
@@ -230,11 +232,13 @@
return textView;
}
+ @Nullable
@Override
public CellLayout getPageAt(int index) {
return (CellLayout) getChildAt(index);
}
+ @Nullable
public CellLayout getCurrentCellLayout() {
return getPageAt(getNextPage());
}
@@ -381,7 +385,7 @@
}
private View getViewInCurrentPage(ToIntFunction<ShortcutAndWidgetContainer> rankProvider) {
- if (getChildCount() < 1) {
+ if (getChildCount() < 1 || getCurrentCellLayout() == null) {
return null;
}
ShortcutAndWidgetContainer container = getCurrentCellLayout().getShortcutsAndWidgets();
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index a6e064a..c554def 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -136,6 +136,7 @@
// Primary user ids
long myProfileId = controller.getSerialNumberForUser(myUserHandle());
long oldProfileId = getDefaultProfileId(db);
+ Log.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
+ 1);
@@ -148,6 +149,8 @@
if (user != null) {
long newManagedProfileId = controller.getSerialNumberForUser(user);
profileMapping.put(oldManagedProfileId, newManagedProfileId);
+ Log.d(TAG, "sanitizeDB: managed profile id=" + oldManagedProfileId
+ + " should be mapped to new id=" + newManagedProfileId);
}
}
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 04f83b9..e5bbcb1 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -60,4 +60,9 @@
* When turned on, we enable Gms Play related logging.
*/
public static final String GMS_PLAY = "GmsPlay";
+
+ /**
+ * When turned on, we enable AGA related session summary logging.
+ */
+ public static final String AGA_SESSION_SUMMARY_LOG = "AGASessionSummaryLog";
}
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 2b67cdd..bcad5de 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -154,6 +154,7 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String VIEW_AND_ACTIVITY_LEAKS = "b/260260325";
public static final String WORK_TAB_MISSING = "b/243688989";
+ public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index c83820b..026766c 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
+import static com.android.launcher3.util.TestUtil.installDummyAppForUser;
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
@@ -39,6 +40,7 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import org.junit.After;
@@ -69,11 +71,11 @@
String[] tokens = output.split("\\s+");
mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
- output = mDevice.executeShellCommand("am start-user " + mProfileUserId);
StringBuilder logStr = new StringBuilder().append("profileId: ").append(mProfileUserId);
for (String str : tokens) {
logStr.append(str).append("\n");
}
+ installDummyAppForUser(mProfileUserId);
updateWorkProfileSetupSuccessful("am start-user", output);
Log.d(WORK_TAB_MISSING, "workProfileSuccessful? " + mWorkProfileSetupSuccessful +
@@ -101,6 +103,7 @@
}
launcher.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
});
+ TestUtil.uninstallDummyApp();
mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
}
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
index 4981795..f8cd995 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -58,8 +58,13 @@
public class TestUtil {
public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
+ public static final int DEFAULT_USER_ID = 0;
public static void installDummyApp() throws IOException {
+ installDummyAppForUser(DEFAULT_USER_ID);
+ }
+
+ public static void installDummyAppForUser(int userId) throws IOException {
// Copy apk from resources to a local file and install from there.
final Resources resources = getContext().getResources();
final InputStream in = resources.openRawResource(
@@ -80,7 +85,7 @@
out.close();
final String result = UiDevice.getInstance(getInstrumentation())
- .executeShellCommand("pm install " + apkFilename);
+ .executeShellCommand("pm install --user " + userId + " " + apkFilename);
Assert.assertTrue(
"Failed to install wellbeing test apk; make sure the device is rooted",
"Success".equals(result.replaceAll("\\s+", "")));
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 19e7b13..7ca6a06 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -2,7 +2,6 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import android.content.Context;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.util.Log;
@@ -54,27 +53,9 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- boolean success = false;
try {
- mDevice.executeShellCommand("cmd statusbar tracing start");
FailureWatcher.super.apply(base, description).evaluate();
- success = true;
} finally {
- // Save artifact for Launcher Winscope trace.
- mDevice.executeShellCommand("cmd statusbar tracing stop");
- final Context nexusLauncherContext =
- getInstrumentation().getTargetContext()
- .createPackageContext("com.google.android.apps.nexuslauncher",
- 0);
- final File launcherTrace =
- new File(nexusLauncherContext.getFilesDir(), "launcher_trace.pb");
- if (success) {
- mDevice.executeShellCommand("rm " + launcherTrace);
- } else {
- mDevice.executeShellCommand("mv " + launcherTrace + " "
- + diagFile(description, "LauncherWinscope", "pb"));
- }
-
// Detect touch events coming from physical screen.
if (mLauncher.hadNontestEvents()) {
throw new AssertionError(
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index e4713b2..0c65539 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -21,6 +21,7 @@
import android.os.Bundle
import androidx.test.core.app.ApplicationProvider
import com.android.app.viewcapture.SimpleViewCapture
+import com.android.app.viewcapture.ViewCapture.MAIN_EXECUTOR
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
import org.junit.rules.TestRule
import org.junit.runner.Description
@@ -69,7 +70,9 @@
// Clean up ViewCapture references here rather than in onActivityDestroyed so
// test code can access view hierarchy capture. onActivityDestroyed would delete
// view capture data before FailureWatcher could output it as a test artifact.
- windowListenerCloseables.onEach(SafeCloseable::close)
+ // This is on the main thread to avoid a race condition where the onDrawListener
+ // is removed while onDraw is running, resulting in an IllegalStateException.
+ MAIN_EXECUTOR.execute { windowListenerCloseables.onEach(SafeCloseable::close) }
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index afeb8d7..2c3c028 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -72,6 +72,44 @@
}
/**
+ * Flings backward (right) and waits the fling's end.
+ */
+ public void flingBackward() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ flingBackwardImpl();
+ }
+ }
+
+ private void flingBackwardImpl() {
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to fling backward in overview")) {
+ LauncherInstrumentation.log("Overview.flingBackward before fling");
+ final UiObject2 overview = verifyActiveContainer();
+ final int rightMargin =
+ mLauncher.getTargetInsets().right + mLauncher.getEdgeSensitivityWidth();
+ mLauncher.scroll(
+ overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20, false);
+ try (LauncherInstrumentation.Closable c2 =
+ mLauncher.addContextLayer("flung backwards")) {
+ verifyActiveContainer();
+ verifyActionsViewVisibility();
+ }
+ }
+ }
+
+ private OverviewTask flingToFirstTask() {
+ OverviewTask currentTask = getCurrentTask();
+
+ while (mLauncher.getRealDisplaySize().x - currentTask.getUiObject().getVisibleBounds().right
+ <= mLauncher.getOverviewPageSpacing()) {
+ flingBackwardImpl();
+ currentTask = getCurrentTask();
+ }
+
+ return currentTask;
+ }
+
+ /**
* Dismissed all tasks by scrolling to Clear-all button and pressing it.
*/
public void dismissAllTasks() {
@@ -94,23 +132,57 @@
}
/**
- * Flings backward (right) and waits the fling's end.
+ * Touch to the right of current task. This should dismiss overview and go back to Workspace.
*/
- public void flingBackward() {
+ public Workspace touchOutsideFirstTask() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c =
- mLauncher.addContextLayer("want to fling backward in overview")) {
- LauncherInstrumentation.log("Overview.flingBackward before fling");
- final UiObject2 overview = verifyActiveContainer();
- final int rightMargin =
- mLauncher.getTargetInsets().right + mLauncher.getEdgeSensitivityWidth();
- mLauncher.scroll(
- overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20, false);
- try (LauncherInstrumentation.Closable c2 =
- mLauncher.addContextLayer("flung backwards")) {
- verifyActiveContainer();
- verifyActionsViewVisibility();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "touching outside the focused task")) {
+
+ if (getTaskCount() < 2) {
+ throw new IllegalStateException(
+ "Need to have at least 2 tasks");
}
+
+ OverviewTask currentTask = flingToFirstTask();
+
+ mLauncher.touchOutsideContainer(currentTask.getUiObject(),
+ /* tapRight= */ true,
+ /* halfwayToEdge= */ false);
+
+ return new Workspace(mLauncher);
+ }
+ }
+
+ /**
+ * Touch between two tasks
+ */
+ public void touchBetweenTasks() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "touching outside the focused task")) {
+ if (getTaskCount() < 2) {
+ throw new IllegalStateException(
+ "Need to have at least 2 tasks");
+ }
+
+ OverviewTask currentTask = flingToFirstTask();
+
+ mLauncher.touchOutsideContainer(currentTask.getUiObject(),
+ /* tapRight= */ false,
+ /* halfwayToEdge= */ false);
+ }
+ }
+
+ /**
+ * Touch either on the right or the left corner of the screen, 1 pixel from the bottom and
+ * from the sides.
+ */
+ public void touchTaskbarBottomCorner(boolean tapRight) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ Taskbar taskbar = new Taskbar(mLauncher);
+ taskbar.touchBottomCorner(tapRight);
+ verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 80fded5..2adfc98 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -2014,21 +2014,41 @@
}
/**
- * Taps outside container to dismiss.
+ * Taps outside container to dismiss, centered vertically and halfway to the edge of the screen.
*
* @param container container to be dismissed
* @param tapRight tap on the right of the container if true, or left otherwise
*/
void touchOutsideContainer(UiObject2 container, boolean tapRight) {
+ touchOutsideContainer(container, tapRight, true);
+ }
+
+ /**
+ * Taps outside the container, to the right or left, and centered vertically.
+ *
+ * @param tapRight if true touches to the right of the container, otherwise touches on left
+ * @param halfwayToEdge if true touches halfway to the screen edge, if false touches 1 px from
+ * container
+ */
+ void touchOutsideContainer(UiObject2 container, boolean tapRight, boolean halfwayToEdge) {
try (LauncherInstrumentation.Closable c = addContextLayer(
"want to tap outside container on the " + (tapRight ? "right" : "left"))) {
Rect containerBounds = getVisibleBounds(container);
+
+ int x;
+ if (halfwayToEdge) {
+ x = tapRight
+ ? (containerBounds.right + getRealDisplaySize().x) / 2
+ : containerBounds.left / 2;
+ } else {
+ x = tapRight
+ ? containerBounds.right + 1
+ : containerBounds.left - 1;
+ }
+ int y = containerBounds.top + containerBounds.height() / 2;
+
final long downTime = SystemClock.uptimeMillis();
- final Point tapTarget = new Point(
- tapRight
- ? (containerBounds.right + getRealDisplaySize().x) / 2
- : containerBounds.left / 2,
- containerBounds.top + 1);
+ final Point tapTarget = new Point(x, y);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
LauncherInstrumentation.GestureScope.INSIDE);
sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 90f3d13..39b93b4 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -71,6 +71,10 @@
return mTask.getVisibleBounds().exactCenterX();
}
+ UiObject2 getUiObject() {
+ return mTask;
+ }
+
/**
* Dismisses the task by swiping up.
*/
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index 6ca7f4b..051630e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.MotionEvent;
@@ -122,4 +123,33 @@
// Look for an icon with no text
return By.clazz(TextView.class).text("");
}
+
+ private Rect getVisibleBounds() {
+ return mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID).getVisibleBounds();
+ }
+
+ /**
+ * Touch either on the right or the left corner of the screen, 1 pixel from the bottom and
+ * from the sides.
+ */
+ void touchBottomCorner(boolean tapRight) {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to tap bottom corner on the " + (tapRight ? "right" : "left"))) {
+ final long downTime = SystemClock.uptimeMillis();
+ final Point tapTarget = new Point(
+ tapRight
+ ?
+ getVisibleBounds().right
+ - mLauncher.getTargetInsets().right
+ - 1
+ : getVisibleBounds().left
+ + 1,
+ mLauncher.getRealDisplaySize().y - 1);
+
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ }
+ }
}