Merge "Re-enable testOverviewForTablet for persistent taskbar." into udc-dev
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index d7de8a7..14605d8 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -45,7 +45,6 @@
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.WAKEUP_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- <uses-permission android:name="android.permission.READ_HOME_APP_SEARCH_DATA" />
<!--
Permissions required for read/write access to the workspace data. These permission name
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index cebcd42..e041bd5 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -135,7 +135,7 @@
}
}
-// Next value 48
+// Next value 50
enum Attribute {
option allow_alias = true;
@@ -190,6 +190,8 @@
// Result sources
DATA_SOURCE_APPSEARCH_APP_PREVIEW = 45;
DATA_SOURCE_APPSEARCH_APP_SRP_PREVIEW = 46;
+ DATA_SOURCE_APPSEARCH_CATEGORY_SRP_PREVIEW = 48;
+ DATA_SOURCE_APPSEARCH_ENTITY_SRP_PREVIEW = 49;
DATA_SOURCE_AIAI_SEARCH_ROOT = 47;
// Web suggestions provided by AGA
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 04e87be..4e67629 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -59,6 +59,29 @@
app:layout_constraintStart_toEndOf="@id/thumbnail1"
app:layout_constraintEnd_toEndOf="parent"/>
+ <ImageView
+ android:id="@+id/icon1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:importantForAccessibility="no"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+
+ <ImageView
+ android:id="@+id/icon2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+
</androidx.constraintlayout.widget.ConstraintLayout>
</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_overview.xml
index 062a9c9..e7b1f23 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview.xml
@@ -41,8 +41,8 @@
android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_marginBottom="8dp"
android:src="@drawable/ic_empty_recents"
+ android:tint="?androidprv:attr/materialColorOnSurface"
- app:tint="?androidprv:attr/materialColorOnSurface"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/text"
@@ -50,7 +50,7 @@
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
- style="@style/KeyboardQuickSwitchOverview"
+ style="@style/KeyboardQuickSwitchText"
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 691df6e..4d213fa 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -59,6 +59,29 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
+ <ImageView
+ android:id="@+id/icon1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:importantForAccessibility="no"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+
+ <ImageView
+ android:id="@+id/icon2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+
</androidx.constraintlayout.widget.ConstraintLayout>
</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
index cd6587c..dde9cac 100644
--- a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
@@ -19,4 +19,5 @@
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@drawable/keyboard_quick_switch_task_view_background"
- android:clipToOutline="true"/>
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 58c0c40..16abdee 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -15,6 +15,7 @@
-->
<com.android.launcher3.taskbar.KeyboardQuickSwitchView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -27,6 +28,43 @@
android:focusableInTouchMode="true"
app:layout_ignoreInsets="true">
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/no_recent_items_pane"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:paddingVertical="@dimen/keyboard_quick_switch_view_spacing"
+ android:alpha="0"
+ android:visibility="gone">
+
+ <ImageView
+ android:id="@+id/no_recent_items_icon"
+ android:layout_width="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
+ android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
+ android:src="@drawable/ic_empty_recents"
+ android:tint="?androidprv:attr/materialColorOnSurfaceInverse"
+ android:importantForAccessibility="no"
+
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/no_recent_items_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/KeyboardQuickSwitchText.OnBackground"
+ android:id="@+id/no_recent_items_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/recents_empty_message"
+
+ app:layout_constraintTop_toBottomOf="@id/no_recent_items_icon"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
<HorizontalScrollView
android:id="@+id/scroll_view"
android:layout_width="wrap_content"
@@ -34,7 +72,7 @@
android:fillViewport="true"
android:scrollbars="none"
android:alpha="0"
- android:visibility="invisible"
+ android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 8e11a2d..9d36c67 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -98,7 +98,7 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте го екранот"</string>
<string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Обука за лентата со задачи"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Повлечете апликација настрана за да користите 2 апликации"</string>
- <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Полека повлечете нагоре за да се прикаже „Лентата со задачи“"</string>
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Полека повлечете нагоре за да се прикаже лентата со задачи"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Добивајте предлози за апликации според вашата рутина"</string>
<string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Вклучете навигација со движење во „Поставки“ за автоматско сокривање на „Лентата со задачи“"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повеќе со една лента со задачи"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d69b155..bb4f74d 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -372,6 +372,8 @@
<dimen name="keyboard_quick_switch_border_width">4dp</dimen>
<dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
<dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_icon_size">28dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_icon_margin">4dp</dimen>
<dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
<dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
<dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
@@ -379,4 +381,6 @@
<dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
<dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
<dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
+ <dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
+ <dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 2b6f749..2d8c45a 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -295,6 +295,7 @@
=1{Show # more app.}
other{Show # more apps.}
}</string>
+
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
</resources>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index e1afb26..ead5343 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -215,13 +215,17 @@
<item name="android:textSize">14sp</item>
</style>
- <style name="KeyboardQuickSwitchOverview">
+ <style name="KeyboardQuickSwitchText">
<item name="fontFamily">google-sans-text</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="lineHeight">20sp</item>
</style>
+ <style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceInverse</item>
+ </style>
+
<style name="GestureTutorialActivity"
parent="@style/AppTheme">
<item name="background">@android:color/transparent</item>
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index c4962cd..7f655cf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -129,8 +129,8 @@
*/
int launchFocusedTask() {
// Return -1 so that the RecentsView is not incorrectly opened when the user closes the
- // quick switch view by tapping the screen.
- return mQuickSwitchViewController == null
+ // quick switch view by tapping the screen or when there are no recent tasks.
+ return mQuickSwitchViewController == null || mTasks.isEmpty()
? -1 : mQuickSwitchViewController.launchFocusedTask();
}
@@ -181,7 +181,7 @@
mModel.getThumbnailCache().updateThumbnailInBackground(task, callback);
}
- void updateTitleInBackground(Task task, Consumer<Task> callback) {
+ void updateIconInBackground(Task task, Consumer<Task> callback) {
mModel.getIconCache().updateIconInBackground(task, callback);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 926ede1..08857b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
@@ -46,6 +47,8 @@
@Nullable private ImageView mThumbnailView1;
@Nullable private ImageView mThumbnailView2;
+ @Nullable private ImageView mIcon1;
+ @Nullable private ImageView mIcon2;
@Nullable private View mContent;
public KeyboardQuickSwitchTaskView(@NonNull Context context) {
@@ -67,6 +70,9 @@
int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ TypedArray ta = context.obtainStyledAttributes(
+ attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);
+
setWillNotDraw(false);
Resources resources = context.getResources();
mBorderAnimator = new BorderAnimator(
@@ -75,17 +81,8 @@
R.dimen.keyboard_quick_switch_border_width),
/* borderRadiusPx= */ resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_task_view_radius),
- /* borderColor= */ attrs == null
- ? DEFAULT_BORDER_COLOR
- : context.getTheme()
- .obtainStyledAttributes(
- attrs,
- R.styleable.TaskView,
- defStyleAttr,
- defStyleRes)
- .getColor(
- R.styleable.TaskView_borderColor,
- DEFAULT_BORDER_COLOR),
+ /* borderColor= */ ta.getColor(
+ R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR),
/* invalidateViewCallback= */ KeyboardQuickSwitchTaskView.this::invalidate,
/* viewScaleTargetProvider= */ new BorderAnimator.ViewScaleTargetProvider() {
@NonNull
@@ -100,14 +97,16 @@
return mContent;
}
});
+ ta.recycle();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
mThumbnailView1 = findViewById(R.id.thumbnail1);
mThumbnailView2 = findViewById(R.id.thumbnail2);
+ mIcon1 = findViewById(R.id.icon1);
+ mIcon2 = findViewById(R.id.icon2);
mContent = findViewById(R.id.content);
}
@@ -126,11 +125,13 @@
@NonNull Task task1,
@Nullable Task task2,
@Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
- @Nullable TitleUpdateFunction titleUpdateFunction) {
+ @Nullable IconUpdateFunction iconUpdateFunction) {
applyThumbnail(mThumbnailView1, task1, thumbnailUpdateFunction);
applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction);
- if (titleUpdateFunction == null) {
+ if (iconUpdateFunction == null) {
+ applyIcon(mIcon1, task1);
+ applyIcon(mIcon2, task2);
setContentDescription(task2 == null
? task1.titleDescription
: getContext().getString(
@@ -139,16 +140,23 @@
task2.titleDescription));
return;
}
- titleUpdateFunction.updateTitleInBackground(task1, t ->
- setContentDescription(task1.titleDescription));
+ iconUpdateFunction.updateIconInBackground(task1, t -> {
+ applyIcon(mIcon1, task1);
+ if (task2 != null) {
+ return;
+ }
+ setContentDescription(task1.titleDescription);
+ });
if (task2 == null) {
return;
}
- titleUpdateFunction.updateTitleInBackground(task2, t ->
- setContentDescription(getContext().getString(
- R.string.quick_switch_split_task,
- task1.titleDescription,
- task2.titleDescription)));
+ iconUpdateFunction.updateIconInBackground(task2, t -> {
+ applyIcon(mIcon2, task2);
+ setContentDescription(getContext().getString(
+ R.string.quick_switch_split_task,
+ task1.titleDescription,
+ task2.titleDescription));
+ });
}
private void applyThumbnail(
@@ -177,13 +185,21 @@
thumbnailView.setImageBitmap(bm);
}
+ private void applyIcon(@Nullable ImageView iconView, @Nullable Task task) {
+ if (iconView == null || task == null) {
+ return;
+ }
+ iconView.setVisibility(VISIBLE);
+ iconView.setImageDrawable(task.icon);
+ }
+
protected interface ThumbnailUpdateFunction {
void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback);
}
- protected interface TitleUpdateFunction {
+ protected interface IconUpdateFunction {
- void updateTitleInBackground(Task task, Consumer<Task> callback);
+ void updateIconInBackground(Task task, Consumer<Task> callback);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 745defc..2cdfb18 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -85,6 +85,8 @@
private final AnimatedFloat mOutlineAnimationProgress = new AnimatedFloat(
this::invalidateOutline);
+ private boolean mDisplayingRecentTasks;
+ private View mNoRecentItemsPane;
private HorizontalScrollView mScrollView;
private ConstraintLayout mContent;
@@ -119,6 +121,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mNoRecentItemsPane = findViewById(R.id.no_recent_items_pane);
mScrollView = findViewById(R.id.scroll_view);
mContent = findViewById(R.id.content);
@@ -145,20 +148,20 @@
taskView.setOnClickListener(v -> mViewCallbacks.launchTappedTask(index));
LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
- // Create a right-to-left ordering of views (or left-to-right in RTL locales)
+ // Create a left-to-right ordering of views (or right-to-left in RTL locales)
if (previousView != null) {
- lp.endToStart = previousView.getId();
+ lp.startToEnd = previousView.getId();
} else {
- lp.endToEnd = PARENT_ID;
+ lp.startToStart = PARENT_ID;
}
lp.topToTop = PARENT_ID;
lp.bottomToBottom = PARENT_ID;
// Add spacing between views
- lp.setMarginEnd(mSpacing);
+ lp.setMarginStart(mSpacing);
if (isFinalView) {
- // Add spacing to the start of the final view so that scrolling ends with some padding.
- lp.startToStart = PARENT_ID;
- lp.setMarginStart(mSpacing);
+ // Add spacing to the end of the final view so that scrolling ends with some padding.
+ lp.endToEnd = PARENT_ID;
+ lp.setMarginEnd(mSpacing);
lp.horizontalBias = 1f;
}
@@ -167,7 +170,7 @@
groupTask.task1,
groupTask.task2,
updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
- updateTasks ? mViewCallbacks::updateTitleInBackground : null);
+ updateTasks ? mViewCallbacks::updateIconInBackground : null);
mContent.addView(taskView, lp);
return taskView;
@@ -187,8 +190,8 @@
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
width, mTaskViewHeight);
- lp.startToStart = PARENT_ID;
- lp.endToStart = previousView.getId();
+ lp.endToEnd = PARENT_ID;
+ lp.startToEnd = previousView.getId();
lp.topToTop = PARENT_ID;
lp.bottomToBottom = PARENT_ID;
lp.setMarginEnd(mSpacing);
@@ -204,10 +207,6 @@
boolean updateTasks,
int currentFocusIndexOverride,
@NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
- if (groupTasks.isEmpty()) {
- // Do not show the quick switch view.
- return;
- }
mViewCallbacks = viewCallbacks;
Resources resources = context.getResources();
int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
@@ -237,6 +236,7 @@
resources.getString(R.string.quick_switch_overflow),
Locale.getDefault()).format(args));
}
+ mDisplayingRecentTasks = !groupTasks.isEmpty();
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@@ -262,13 +262,16 @@
alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
closeAnimation.play(alphaAnimation);
+ View displayedContent = mDisplayingRecentTasks ? mScrollView : mNoRecentItemsPane;
Animator translationYAnimation = ObjectAnimator.ofFloat(
- mScrollView, TRANSLATION_Y, 0, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP));
+ displayedContent,
+ TRANSLATION_Y,
+ 0, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP));
translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
translationYAnimation.setInterpolator(CLOSE_TRANSLATION_Y_INTERPOLATOR);
closeAnimation.play(translationYAnimation);
- Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 1f, 0f);
+ Animator contentAlphaAnimation = ObjectAnimator.ofFloat(displayedContent, ALPHA, 1f, 0f);
contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
closeAnimation.play(contentAlphaAnimation);
@@ -300,19 +303,24 @@
alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
mOpenAnimation.play(alphaAnimation);
+ View displayedContent = mDisplayingRecentTasks ? mScrollView : mNoRecentItemsPane;
Animator translationXAnimation = ObjectAnimator.ofFloat(
- mScrollView, TRANSLATION_X, -Utilities.dpToPx(CONTENT_START_TRANSLATION_X_DP), 0);
+ displayedContent,
+ TRANSLATION_X,
+ -Utilities.dpToPx(CONTENT_START_TRANSLATION_X_DP), 0);
translationXAnimation.setDuration(CONTENT_TRANSLATION_X_ANIMATION_DURATION_MS);
translationXAnimation.setInterpolator(OPEN_TRANSLATION_X_INTERPOLATOR);
mOpenAnimation.play(translationXAnimation);
Animator translationYAnimation = ObjectAnimator.ofFloat(
- mScrollView, TRANSLATION_Y, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP), 0);
+ displayedContent,
+ TRANSLATION_Y,
+ -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP), 0);
translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
translationYAnimation.setInterpolator(OPEN_TRANSLATION_Y_INTERPOLATOR);
mOpenAnimation.play(translationYAnimation);
- Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 0f, 1f);
+ Animator contentAlphaAnimation = ObjectAnimator.ofFloat(displayedContent, ALPHA, 0f, 1f);
contentAlphaAnimation.setStartDelay(CONTENT_ALPHA_ANIMATION_START_DELAY_MS);
contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
mOpenAnimation.play(contentAlphaAnimation);
@@ -353,7 +361,7 @@
} else {
animateFocusMove(-1, currentFocusIndexOverride);
}
- mScrollView.setVisibility(VISIBLE);
+ displayedContent.setVisibility(VISIBLE);
setVisibility(VISIBLE);
requestFocus();
}
@@ -372,6 +380,9 @@
}
protected void animateFocusMove(int fromIndex, int toIndex) {
+ if (!mDisplayingRecentTasks) {
+ return;
+ }
KeyboardQuickSwitchTaskView focusedTask = getTaskAt(toIndex);
if (focusedTask == null) {
return;
@@ -402,16 +413,16 @@
} else if (toIndex > fromIndex || toIndex == 0) {
// Scrolling to next task view
if (mIsRtl) {
- scrollRightTo(focusedTask);
- } else {
scrollLeftTo(focusedTask);
+ } else {
+ scrollRightTo(focusedTask);
}
} else {
// Scrolling to previous task view
if (mIsRtl) {
- scrollLeftTo(focusedTask);
- } else {
scrollRightTo(focusedTask);
+ } else {
+ scrollLeftTo(focusedTask);
}
}
if (mViewCallbacks != null) {
@@ -425,11 +436,15 @@
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- return (mViewCallbacks != null && mViewCallbacks.onKeyUp(keyCode, event, mIsRtl))
+ return (mViewCallbacks != null
+ && mViewCallbacks.onKeyUp(keyCode, event, mIsRtl, mDisplayingRecentTasks))
|| super.onKeyUp(keyCode, event);
}
private void initializeScroll(int index, boolean shouldTruncateTarget) {
+ if (!mDisplayingRecentTasks) {
+ return;
+ }
View task = getTaskAt(index);
if (task == null) {
return;
@@ -449,6 +464,9 @@
private void scrollRightTo(
@NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+ if (!mDisplayingRecentTasks) {
+ return;
+ }
if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
return;
}
@@ -468,6 +486,9 @@
private void scrollLeftTo(
@NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+ if (!mDisplayingRecentTasks) {
+ return;
+ }
if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
return;
}
@@ -491,7 +512,7 @@
@Nullable
protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
- return index < 0 || index >= mContent.getChildCount()
+ return !mDisplayingRecentTasks || index < 0 || index >= mContent.getChildCount()
? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index c1f764f..7bd8898 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -169,7 +169,7 @@
class ViewCallbacks {
- boolean onKeyUp(int keyCode, KeyEvent event, boolean isRTL) {
+ boolean onKeyUp(int keyCode, KeyEvent event, boolean isRTL, boolean allowTraversal) {
if (keyCode != KeyEvent.KEYCODE_TAB
&& keyCode != KeyEvent.KEYCODE_DPAD_RIGHT
&& keyCode != KeyEvent.KEYCODE_DPAD_LEFT
@@ -181,6 +181,9 @@
closeQuickSwitchView(true);
return true;
}
+ if (!allowTraversal) {
+ return false;
+ }
boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
|| (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !isRTL)
|| (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && isRTL);
@@ -195,6 +198,9 @@
// focus a less recent app or loop back to the opposite end
: ((mCurrentFocusIndex + 1) % taskCount));
+ if (mCurrentFocusIndex == toIndex) {
+ return true;
+ }
mKeyboardQuickSwitchView.animateFocusMove(mCurrentFocusIndex, toIndex);
return true;
@@ -213,8 +219,8 @@
mControllerCallbacks.updateThumbnailInBackground(task, callback);
}
- void updateTitleInBackground(Task task, Consumer<Task> callback) {
- mControllerCallbacks.updateTitleInBackground(task, callback);
+ void updateIconInBackground(Task task, Consumer<Task> callback) {
+ mControllerCallbacks.updateIconInBackground(task, callback);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index cf82900..a1c9f05 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -21,6 +21,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -43,6 +44,7 @@
import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -95,10 +97,13 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
+import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
import com.android.launcher3.util.TraceHelper;
@@ -567,6 +572,22 @@
}
}
+ @Override
+ public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
+ RunnableList callbacks = new RunnableList();
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(
+ this, 0, 0, Color.TRANSPARENT,
+ Executors.MAIN_EXECUTOR.getHandler(), null,
+ elapsedRealTime -> callbacks.executeAllAndDestroy());
+ options.setSplashScreenStyle(splashScreenStyle);
+ return new ActivityOptionsWrapper(options, callbacks);
+ }
+
+ @Override
+ public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
+ return makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED);
+ }
+
/**
* Sets a new data-source for this taskbar instance
*/
@@ -979,11 +1000,16 @@
mControllers.taskbarEduTooltipController.hide();
}
- /** Returns {@code true} if taskbar All Apps is open. */
+ /** Returns {@code true} if Taskbar All Apps is open. */
public boolean isTaskbarAllAppsOpen() {
return mControllers.taskbarAllAppsController.isOpen();
}
+ /** Toggles the Taskbar's stash state. */
+ public void toggleTaskbarStash() {
+ mControllers.taskbarStashController.toggleTaskbarStash();
+ }
+
/**
* Called to start the taskbar translation spring to its settled translation (0).
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 88fea31..0a83279 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -36,6 +36,7 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.util.Log;
import android.util.Pair;
import android.view.DragEvent;
import android.view.MotionEvent;
@@ -87,6 +88,7 @@
*/
public class TaskbarDragController extends DragController<BaseTaskbarContext> implements
TaskbarControllers.LoggableTaskbarController {
+ private static final String TAG = "TaskbarDragController";
private static final boolean DEBUG_DRAG_SHADOW_SURFACE = false;
private static final int ANIM_DURATION_RETURN_ICON_TO_TASKBAR = 300;
@@ -318,12 +320,26 @@
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
int iconSize = Math.max(mDragIconSize, btv.getWidth());
- shadowSize.set(iconSize, iconSize);
+ if (iconSize > 0) {
+ shadowSize.set(iconSize, iconSize);
+ } else {
+ Log.d(TAG, "Invalid icon size, dragSize=" + mDragIconSize
+ + " viewWidth=" + btv.getWidth());
+ }
+
// The registration point was taken before the icon scaled to mDragIconSize, so
// offset the registration to where the touch is on the new size.
int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
int offsetY = (mDragIconSize - mDragObject.dragView.getDragRegionHeight()) / 2;
- shadowTouchPoint.set(mRegistrationX + offsetX, mRegistrationY + offsetY);
+ int touchX = mRegistrationX + offsetX;
+ int touchY = mRegistrationY + offsetY;
+ if (touchX >= 0 && touchY >= 0) {
+ shadowTouchPoint.set(touchX, touchY);
+ } else {
+ Log.d(TAG, "Invalid touch point, "
+ + "registrationXY=(" + mRegistrationX + ", " + mRegistrationY + ") "
+ + "offsetXY=(" + offsetX + ", " + offsetY + ")");
+ }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index dfbd5bb..008f5f6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -474,8 +474,7 @@
public void onAnimationEnd(Animator animation) {
TaskbarStashController stashController =
mControllers.taskbarStashController;
- stashController.updateAndAnimateTransientTaskbar(
- /* stash */ true, /* duration */ 0);
+ stashController.updateAndAnimateTransientTaskbar(/* stash */ true);
}
});
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 1727dd3..6f82c7d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -501,16 +501,9 @@
}
/**
- * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
- */
- public void updateAndAnimateTransientTaskbar(boolean stash) {
- updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION);
- }
-
- /**
* Stash or unstashes the transient taskbar.
*/
- public void updateAndAnimateTransientTaskbar(boolean stash, long duration) {
+ public void updateAndAnimateTransientTaskbar(boolean stash) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
@@ -575,6 +568,12 @@
return false;
}
+ /** Toggles the Taskbar's stash state. */
+ public void toggleTaskbarStash() {
+ if (!DisplayController.isTransientTaskbar(mActivity) || !hasAnyFlag(FLAGS_IN_APP)) return;
+ updateAndAnimateTransientTaskbar(!hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
+ }
+
/**
* Adds the Taskbar unstash to Hotseat animator to the animator set.
*
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 65f449c..79a301a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -68,6 +68,7 @@
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.SensorManager;
@@ -143,6 +144,7 @@
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.ObjectWrapper;
@@ -343,14 +345,16 @@
}
@Override
- public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
+ public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
// Only pause is taskbar controller is not present
mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
- boolean started = super.startActivitySafely(v, intent, item);
- if (getTaskbarUIController() == null && !started) {
+ RunnableList result = super.startActivitySafely(v, intent, item);
+ if (getTaskbarUIController() == null && result == null) {
mHotseatPredictionController.setPauseUIUpdate(false);
+ } else {
+ result.add(() -> mHotseatPredictionController.setPauseUIUpdate(false));
}
- return started;
+ return result;
}
@Override
@@ -370,11 +374,6 @@
| ACTIVITY_STATE_USER_ACTIVE | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) {
onStateOrResumeChanging((getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0);
}
-
- if (((changeBits & ACTIVITY_STATE_STARTED) != 0
- || (changeBits & getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) {
- mHotseatPredictionController.setPauseUIUpdate(false);
- }
}
@Override
@@ -1102,6 +1101,17 @@
}
@Override
+ public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
+ RunnableList callbacks = new RunnableList();
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(
+ this, 0, 0, Color.TRANSPARENT,
+ Executors.MAIN_EXECUTOR.getHandler(), null,
+ elapsedRealTime -> callbacks.executeAllAndDestroy());
+ options.setSplashScreenStyle(splashScreenStyle);
+ return new ActivityOptionsWrapper(options, callbacks);
+ }
+
+ @Override
@BinderThread
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 40dfd82..8cbd6e8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -41,11 +41,9 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.TaskUtils;
-import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
@@ -108,11 +106,6 @@
if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, typeToClose) != null) {
return true;
}
- if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
- && TopTaskTracker.INSTANCE.get(mLauncher).getCachedTopTask(false)
- .isExcludedAssistant()) {
- return true;
- }
return false;
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index c8c6292..4c4b9b4 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -236,6 +236,9 @@
homeIsOnTop = true;
}
}
+ if (activityInterface.allowAllAppsFromOverview()) {
+ homeIsOnTop = true;
+ }
if (!homeIsOnTop) {
options.setTransientLaunch();
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 99a57a2..1fbfbe6 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -24,7 +24,6 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
-import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
@@ -85,6 +84,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -207,7 +207,15 @@
@BinderThread
@Override
public void onTaskbarToggled() {
- // To be implemented.
+ if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get()) return;
+ MAIN_EXECUTOR.execute(() -> {
+ TaskbarActivityContext activityContext =
+ mTaskbarManager.getCurrentActivityContext();
+
+ if (activityContext != null) {
+ activityContext.toggleTaskbarStash();
+ }
+ });
}
@BinderThread
@@ -1089,22 +1097,17 @@
boolean hasWindowFocus = activity.getRootView().hasWindowFocus();
boolean isPreviousGestureAnimatingToLauncher =
previousGestureState.isRunningAnimationToLauncher();
- boolean forcingOverviewInputConsumer =
- ASSISTANT_GIVES_LAUNCHER_FOCUS.get() && forceOverviewInputConsumer;
boolean isInLiveTileMode = gestureState.getActivityInterface().isInLiveTileMode();
reasonString.append(SUBSTRING_PREFIX)
.append(hasWindowFocus
? "activity has window focus"
: (isPreviousGestureAnimatingToLauncher
? "previous gesture is still animating to launcher"
- : (forcingOverviewInputConsumer
- ? "assistant gives launcher focus and forcing focus"
- : (isInLiveTileMode
- ? "device is in live mode"
- : "all overview focus conditions failed"))));
+ : isInLiveTileMode
+ ? "device is in live mode"
+ : "all overview focus conditions failed"));
if (hasWindowFocus
|| isPreviousGestureAnimatingToLauncher
- || forcingOverviewInputConsumer
|| isInLiveTileMode) {
reasonString.append(SUBSTRING_PREFIX)
.append("overview should have focus, using OverviewInputConsumer");
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 2008129..4dbf4e3 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
@@ -133,7 +134,8 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == NORMAL || finalState == SPRING_LOADED || finalState == ALL_APPS) {
+ if (finalState == NORMAL || finalState == SPRING_LOADED || finalState == EDIT_MODE
+ || finalState == ALL_APPS) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index d570708..c47c946 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -45,6 +45,7 @@
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -438,6 +439,9 @@
setWillNotDraw(!keyboardFocusHighlightEnabled);
+ TypedArray ta = context.obtainStyledAttributes(
+ attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);
+
mBorderAnimator = !keyboardFocusHighlightEnabled
? null
: new BorderAnimator(
@@ -445,18 +449,10 @@
/* borderWidthPx= */ context.getResources().getDimensionPixelSize(
R.dimen.keyboard_quick_switch_border_width),
/* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
- /* borderColor= */ attrs == null
- ? DEFAULT_BORDER_COLOR
- : context.getTheme()
- .obtainStyledAttributes(
- attrs,
- R.styleable.TaskView,
- defStyleAttr,
- defStyleRes)
- .getColor(
- R.styleable.TaskView_borderColor,
- DEFAULT_BORDER_COLOR),
+ /* borderColor= */ ta.getColor(
+ R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR),
/* invalidateViewCallback= */ TaskView.this::invalidate);
+ ta.recycle();
}
protected void updateBorderBounds(Rect bounds) {
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 62d46d3..97e34c5 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -62,6 +62,7 @@
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.rule.ViewCaptureRule;
import com.android.quickstep.views.RecentsView;
import org.junit.After;
@@ -115,10 +116,12 @@
Utilities.enableRunningInTestHarnessForTests();
}
+ final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
mOrderSensitiveRules = RuleChain
.outerRule(new SamplerRule())
.around(new NavigationModeSwitchRule(mLauncher))
- .around(new FailureWatcher(mDevice, mLauncher));
+ .around(viewCaptureRule)
+ .around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()));
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
diff --git a/res/color-night-v31/folder_background_dark.xml b/res/color-night-v31/folder_background_dark.xml
index 696e8ea..f415210 100644
--- a/res/color-night-v31/folder_background_dark.xml
+++ b/res/color-night-v31/folder_background_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
- android:color="@android:color/system_neutral2_500"
- android:lStar="35" />
+ android:color="@android:color/system_neutral2_900"
+ android:lStar="12" />
</selector>
diff --git a/res/color-night-v31/folder_preview_dark.xml b/res/color-night-v31/folder_preview_dark.xml
index bdd48a2..644d61a 100644
--- a/res/color-night-v31/folder_preview_dark.xml
+++ b/res/color-night-v31/folder_preview_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
- android:color="@android:color/system_neutral2_500"
- android:lStar="30" />
+ android:color="@android:color/system_neutral1_900"
+ android:lStar="17" />
</selector>
diff --git a/res/color-v31/folder_background_light.xml b/res/color-v31/folder_background_light.xml
index eb2fdd7..4dd088b 100644
--- a/res/color-v31/folder_background_light.xml
+++ b/res/color-v31/folder_background_light.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
- android:color="@android:color/system_neutral1_500"
- android:lStar="98" />
+ android:color="@android:color/system_neutral1_50"
+ android:lStar="94" />
</selector>
diff --git a/res/color-v31/folder_preview_light.xml b/res/color-v31/folder_preview_light.xml
index ed1205e..6727b24 100644
--- a/res/color-v31/folder_preview_light.xml
+++ b/res/color-v31/folder_preview_light.xml
@@ -14,7 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@android:color/system_accent2_500"
- android:lStar="80" />
+ <item android:color="@android:color/system_accent2_200"/>
</selector>
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 5518dc8..31f4870 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -51,7 +51,7 @@
android:singleLine="true"
android:textColor="?attr/folderTextColor"
android:textColorHighlight="?android:attr/colorControlHighlight"
- android:textColorHint="?attr/folderHintColor"/>
+ android:textColorHint="?attr/folderHintTextColor"/>
<com.android.launcher3.pageindicators.PageIndicatorDots
android:id="@+id/folder_page_indicator"
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 1b211f1..4d617c5 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -50,8 +50,7 @@
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Pertsonalak"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Lanekoak"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Elkarrizketak"</string>
- <!-- no translation found for widget_category_note_taking (3469689394504266039) -->
- <skip />
+ <string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
<string name="widget_education_header" msgid="4874760613775913787">"Informazio erabilgarria beti eskura"</string>
<string name="widget_education_content" msgid="1731667670753497052">"Aplikaziorik ireki beharrik gabe informazioa zuzenean jasotzeko, gehitu widgetak hasierako pantailan"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Sakatu hau widgeten ezarpenak aldatzeko"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index de60f3a..c2ee822 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -83,7 +83,7 @@
<string name="permlab_write_settings" msgid="4820028712156303762">"да пишува поставки и кратенки на почетна страница"</string>
<string name="permdesc_write_settings" msgid="726859348127868466">"Овозможува апликацијата да ги менува поставките и кратенките на почетната страница."</string>
<string name="gadget_error_text" msgid="740356548025791839">"Не може да се вчита виџетот"</string>
- <string name="gadget_setup_text" msgid="8348374825537681407">"Поставки за виџет"</string>
+ <string name="gadget_setup_text" msgid="8348374825537681407">"Поставки за виџетот"</string>
<string name="gadget_complete_setup_text" msgid="309040266978007925">"Допрете за да го завршите поставувањето"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"Ова е системска апликација и не може да се деинсталира."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"Изменете го името"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 1d4b989..b4515a0 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -91,7 +91,7 @@
<string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} संबंधित # सूचना आहे}other{{app_name} संबंधित # सूचना आहेत}}"</string>
<string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पेज"</string>
<string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"नवीन मुख्य स्क्रीन पेज"</string>
+ <string name="workspace_new_page" msgid="257366611030256142">"नवीन होम स्क्रीन पेज"</string>
<string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
<string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डर बंद करण्यासाठी टॅप करा"</string>
<string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे सेव्ह करण्यासाठी टॅप करा"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 0c036ff..9f09b99 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -34,8 +34,10 @@
<color name="workspace_text_color_light">@android:color/system_neutral1_0</color>
<color name="workspace_text_color_dark">@android:color/system_neutral1_1000</color>
- <color name="folder_hint_text_color_light">@android:color/system_neutral1_50</color>
- <color name="folder_hint_text_color_dark">@android:color/system_neutral2_700</color>
+ <color name="folder_text_color_light">@android:color/system_neutral1_900</color>
+ <color name="folder_text_color_dark">@android:color/system_neutral1_100</color>
+ <color name="folder_hint_text_color_light">@android:color/system_neutral2_700</color>
+ <color name="folder_hint_text_color_dark">@android:color/system_neutral2_200</color>
<color name="text_color_primary_dark">@android:color/system_neutral1_50</color>
<color name="text_color_secondary_dark">@android:color/system_neutral2_200</color>
@@ -44,7 +46,7 @@
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
<color name="folder_pagination_color_light">@android:color/system_accent1_600</color>
- <color name="folder_pagination_color_dark">@android:color/system_accent2_100</color>
+ <color name="folder_pagination_color_dark">@android:color/system_accent1_200</color>
<color name="home_settings_header_accent">@android:color/system_accent1_600</color>
<color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 418f5a7..0772557 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -48,7 +48,7 @@
<attr name="folderIconRadius" format="float" />
<attr name="folderIconBorderColor" format="color" />
<attr name="folderTextColor" format="color" />
- <attr name="folderHintColor" format="color" />
+ <attr name="folderHintTextColor" format="color" />
<attr name="isFolderDarkText" format="boolean" />
<attr name="workspaceAccentColor" format="color" />
<attr name="dropTargetHoverTextColor" format="color" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b1bff18..2295043 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -60,17 +60,19 @@
<color name="workspace_text_color_light">#FFF</color>
<color name="workspace_text_color_dark">#FF000000</color>
- <color name="folder_hint_text_color_light">#FFF</color>
- <color name="folder_hint_text_color_dark">#FF000000</color>
+ <color name="folder_text_color_light">#1F1F1F</color>
+ <color name="folder_text_color_dark">#E3E3E3</color>
+ <color name="folder_hint_text_color_light">#444746</color>
+ <color name="folder_hint_text_color_dark">#C4C7C5</color>
- <color name="folder_background_light">#F9F9F9</color>
- <color name="folder_background_dark">#464746</color>
+ <color name="folder_background_light">#EFEDED</color>
+ <color name="folder_background_dark">#1F2020</color>
- <color name="folder_preview_light">#F9F9F9</color>
- <color name="folder_preview_dark">#464746</color>
+ <color name="folder_preview_light">#7FCFFF</color>
+ <color name="folder_preview_dark">#2A2A2A</color>
- <color name="folder_pagination_color_light">#ff006c5f</color>
- <color name="folder_pagination_color_dark">#ffbfebe3</color>
+ <color name="folder_pagination_color_light">#0B57D0</color>
+ <color name="folder_pagination_color_dark">#A8C7FA</color>
<color name="text_color_primary_dark">#FFFFFFFF</color>
<color name="text_color_secondary_dark">#FFFFFFFF</color>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8f75550..d0f2067 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -54,9 +54,9 @@
<item name="folderPreviewColor">@color/folder_preview_light</item>
<item name="folderBackgroundColor">@color/folder_background_light</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
- <item name="folderTextColor">?android:attr/textColorPrimary</item>
<item name="isFolderDarkText">true</item>
- <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
+ <item name="folderTextColor">@color/folder_text_color_light</item>
+ <item name="folderHintTextColor">@color/folder_hint_text_color_light</item>
<item name="loadingIconColor">#CCFFFFFF</item>
<item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
<item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
@@ -116,7 +116,8 @@
<item name="folderBackgroundColor">@color/folder_background_dark</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
<item name="isFolderDarkText">false</item>
- <item name="folderHintColor">@color/folder_hint_text_color_light</item>
+ <item name="folderTextColor">@color/folder_text_color_dark</item>
+ <item name="folderHintTextColor">@color/folder_hint_text_color_dark</item>
<item name="isMainColorDark">true</item>
<item name="loadingIconColor">#99FFFFFF</item>
<item name="iconOnlyShortcutColor">#B3FFFFFF</item>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 45b03c2..8876a1b 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -156,6 +156,13 @@
}
@Override
+ public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
+ ActivityOptionsWrapper wrapper = super.makeDefaultActivityOptions(splashScreenStyle);
+ addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
+ return wrapper;
+ }
+
+ @Override
protected void onStart() {
super.onStart();
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5163ede..6763eaf 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -18,6 +18,7 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -571,7 +572,9 @@
}
protected void updateBgAlpha() {
- mBackground.setAlpha((int) (mSpringLoadedProgress * 255));
+ if (!getWorkspace().mLauncher.isInState(EDIT_MODE)) {
+ mBackground.setAlpha((int) (mSpringLoadedProgress * 255));
+ }
}
/**
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0231090..fb41044 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,7 +55,10 @@
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.ResourceHelper;
import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.workspace.CalculatedWorkspaceSpec;
+import com.android.launcher3.workspace.WorkspaceSpecs;
import java.io.PrintWriter;
import java.util.Locale;
@@ -101,9 +104,14 @@
public final float aspectRatio;
public final boolean isScalableGrid;
- public final boolean isResponsiveGrid;
private final int mTypeIndex;
+ // Responsive grid
+ private final boolean mIsResponsiveGrid;
+ private WorkspaceSpecs mWorkspaceSpecs;
+ private CalculatedWorkspaceSpec mResponsiveWidthSpec;
+ private CalculatedWorkspaceSpec mResponsiveHeightSpec;
+
/**
* The maximum amount of left/right workspace padding as a percentage of the screen width.
* To be clear, this means that up to 7% of the screen width can be used as left padding, and
@@ -294,9 +302,8 @@
this.rotationHint = windowBounds.rotationHint;
mInsets.set(windowBounds.insets);
- // TODO(b/241386436):
- // for testing that the flag works only, shouldn't change any launcher behaviour
- isResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
+ // TODO(b/241386436): shouldn't change any launcher behaviour
+ mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
// Determine device posture.
@@ -335,6 +342,14 @@
}
}
+ if (mIsResponsiveGrid) {
+ mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId));
+ mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns,
+ availableWidthPx);
+ mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows,
+ availableHeightPx);
+ }
+
if (DisplayController.isTransientTaskbar(context)) {
float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
@@ -1582,7 +1597,7 @@
writer.println(prefix + "\taspectRatio:" + aspectRatio);
- writer.println(prefix + "\tisResponsiveGrid:" + isResponsiveGrid);
+ writer.println(prefix + "\tisResponsiveGrid:" + mIsResponsiveGrid);
writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);
writer.println(prefix + "\tinv.numRows: " + inv.numRows);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ffd56cc..0b75c45 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -34,6 +34,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -44,6 +45,7 @@
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
+import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -901,12 +903,8 @@
final int pendingAddWidgetId = requestArgs.getWidgetId();
- Runnable exitSpringLoaded = new Runnable() {
- @Override
- public void run() {
- mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
- }
- };
+ Runnable exitSpringLoaded = MULTI_SELECT_EDIT_MODE.get() ? null
+ : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
if (requestCode == REQUEST_BIND_APPWIDGET) {
// This is called only if the user did not previously have permissions to bind widgets
@@ -1040,10 +1038,9 @@
final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId,
requestArgs.getWidgetHandler().getProviderInfo(this));
boundWidget = layout;
- onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- completeAddAppWidget(appWidgetId, requestArgs, layout, null);
+ onCompleteRunnable = () -> {
+ completeAddAppWidget(appWidgetId, requestArgs, layout, null);
+ if (!isInState(EDIT_MODE)) {
mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
}
};
@@ -1178,7 +1175,7 @@
}
addActivityFlags(ACTIVITY_STATE_TRANSITION_ACTIVE);
- if (state == SPRING_LOADED) {
+ if (state == SPRING_LOADED || state == EDIT_MODE) {
// Prevent any Un/InstallShortcutReceivers from updating the db while we are
// not on homescreen
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_DRAG_AND_DROP);
@@ -1532,7 +1529,8 @@
mStateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- if (mPrevLauncherState == SPRING_LOADED && finalState == NORMAL) {
+ if ((mPrevLauncherState == SPRING_LOADED || mPrevLauncherState == EDIT_MODE)
+ && finalState == NORMAL) {
AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
mStateManager.removeStateListener(this);
}
@@ -1900,13 +1898,9 @@
REQUEST_CREATE_APPWIDGET)) {
// If the configuration flow was not started, add the widget
- Runnable onComplete = new Runnable() {
- @Override
- public void run() {
- // Exit spring loaded mode if necessary after adding the widget
- mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
- }
- };
+ // Exit spring loaded mode if necessary after adding the widget
+ Runnable onComplete = MULTI_SELECT_EDIT_MODE.get() ? null
+ : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
completeAddAppWidget(appWidgetId, info, boundWidget,
addFlowHandler.getProviderInfo(this));
mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
@@ -2154,30 +2148,38 @@
}
@Override
- public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
+ public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
if (!hasBeenResumed()) {
+ RunnableList result = new RunnableList();
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
- addOnResumeCallback(() -> startActivitySafely(v, intent, item));
+ addOnResumeCallback(() -> {
+ RunnableList actualResult = startActivitySafely(v, intent, item);
+ if (actualResult != null) {
+ actualResult.add(result::executeAllAndDestroy);
+ } else {
+ result.executeAllAndDestroy();
+ }
+ });
if (mOnDeferredActivityLaunchCallback != null) {
mOnDeferredActivityLaunchCallback.run();
mOnDeferredActivityLaunchCallback = null;
}
- return true;
+ return result;
}
- boolean success = super.startActivitySafely(v, intent, item);
- if (success && v instanceof BubbleTextView) {
+ RunnableList result = super.startActivitySafely(v, intent, item);
+ if (result != null && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
- addOnResumeCallback(() -> btv.setStayPressed(false));
+ result.add(() -> btv.setStayPressed(false));
}
- return success;
+ return result;
}
boolean isHotseatLayout(View layout) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 65870d3..617afcb 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -92,6 +92,15 @@
static final String TAG = "Launcher.Model";
+ // Broadcast intent to track when the profile gets locked:
+ // ACTION_MANAGED_PROFILE_UNAVAILABLE can be used until Android U where profile no longer gets
+ // locked when paused.
+ // ACTION_PROFILE_INACCESSIBLE always means that the profile is getting locked but it only
+ // appeared in Android S.
+ private static final String ACTION_PROFILE_LOCKED = Utilities.ATLEAST_U
+ ? Intent.ACTION_PROFILE_INACCESSIBLE
+ : Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
+
@NonNull
private final LauncherAppState mApp;
@NonNull
@@ -290,9 +299,9 @@
// If we have changed locale we need to clear out the labels in all apps/workspace.
forceReload();
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
- || Intent.ACTION_PROFILE_INACCESSIBLE.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)
- || Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
+ || Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)
+ || Intent.ACTION_PROFILE_INACCESSIBLE.equals(action)) {
UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.WORK_TAB_MISSING, "onBroadcastIntent intentAction: " + action +
@@ -305,9 +314,7 @@
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE, user));
}
- // ACTION_PROFILE_INACCESSIBLE sends the profile back to locked mode, so
- // we need to run the state change task again.
- if (Intent.ACTION_PROFILE_INACCESSIBLE.equals(action)
+ if (ACTION_PROFILE_LOCKED.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
enqueueModelUpdateTask(new UserLockStateChangedTask(
user, Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)));
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index b8d13ed..8b124dc 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.EDIT_MODE_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -38,6 +39,7 @@
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.states.EditModeState;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -103,7 +105,7 @@
}
};
- private static final LauncherState[] sAllStates = new LauncherState[10];
+ private static final LauncherState[] sAllStates = new LauncherState[11];
/**
* TODO: Create a separate class for NORMAL state.
@@ -123,6 +125,7 @@
*/
public static final LauncherState SPRING_LOADED = new SpringLoadedState(
SPRING_LOADED_STATE_ORDINAL);
+ public static final LauncherState EDIT_MODE = new EditModeState(EDIT_MODE_STATE_ORDINAL);
public static final LauncherState ALL_APPS = new AllAppsState(ALL_APPS_STATE_ORDINAL);
public static final LauncherState HINT_STATE = new HintState(HINT_STATE_ORDINAL);
public static final LauncherState HINT_STATE_TWO_BUTTON = new HintState(
@@ -328,7 +331,9 @@
* Gets the translation provider for workspace pages.
*/
public PageTranslationProvider getWorkspacePageTranslationProvider(Launcher launcher) {
- if (this != SPRING_LOADED || !launcher.getDeviceProfile().isTwoPanels) {
+ if (this != SPRING_LOADED
+ || this != EDIT_MODE
+ || !launcher.getDeviceProfile().isTwoPanels) {
return DEFAULT_PAGE_TRANSLATION_PROVIDER;
}
final float quarterPageSpacing = launcher.getWorkspace().getPageSpacing() / 4f;
@@ -343,6 +348,16 @@
};
}
+ /**
+ * Called when leaving this LauncherState
+ * @param launcher - Launcher instance
+ * @param toState - New LauncherState that is being entered
+ */
+ public void onLeavingState(Launcher launcher, LauncherState toState) {
+ // no-op
+ // override to handle when leaving current LauncherState
+ }
+
@Override
public LauncherState getHistoryForState(LauncherState previousState) {
// No history is supported
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2fa1a57..73bb828 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_INACCESSIBLE;
@@ -494,8 +495,9 @@
}
}
- // Always enter the spring loaded mode
- mLauncher.getStateManager().goToState(SPRING_LOADED);
+ if (!mLauncher.isInState(EDIT_MODE)) {
+ mLauncher.getStateManager().goToState(SPRING_LOADED);
+ }
mStatsLogManager.logger().withItemInfo(dragObject.dragInfo)
.withInstanceId(dragObject.logInstanceId)
.log(LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED);
@@ -1432,7 +1434,8 @@
}
private boolean workspaceInScrollableState() {
- return mLauncher.isInState(SPRING_LOADED) || !workspaceInModalState();
+ return mLauncher.isInState(SPRING_LOADED) || mLauncher.isInState(EDIT_MODE)
+ || !workspaceInModalState();
}
/**
@@ -1526,6 +1529,7 @@
@Override
public void setState(LauncherState toState) {
onStartStateTransition();
+ mLauncher.getStateManager().getState().onLeavingState(mLauncher, toState);
mStateTransitionAnimation.setState(toState);
onEndStateTransition();
}
@@ -1537,6 +1541,7 @@
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
StateTransitionListener listener = new StateTransitionListener();
+ mLauncher.getStateManager().getState().onLeavingState(mLauncher, toState);
mStateTransitionAnimation.setStateWithAnimation(toState, config, animation);
// Invalidate the pages now, so that we have the visible pages before the
@@ -1999,7 +2004,9 @@
distance, false, d)
|| addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
distance, d, false)) {
- mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ if (!mLauncher.isInState(EDIT_MODE)) {
+ mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ }
return;
}
@@ -2128,14 +2135,19 @@
// spring-loaded mode so the page meets the icon where it was picked up.
final RunnableList callbackList = new RunnableList();
final Runnable onCompleteCallback = onCompleteRunnable;
+ LauncherState currentState = mLauncher.getStateManager().getState();
mLauncher.getDragController().animateDragViewToOriginalPosition(
/* onComplete= */ callbackList::executeAllAndDestroy, cell,
- SPRING_LOADED.getTransitionDuration(mLauncher, true /* isToState */));
- mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
- onCompleteCallback == null
- ? null
- : forSuccessCallback(
- () -> callbackList.add(onCompleteCallback)));
+ currentState.getTransitionDuration(mLauncher, true /* isToState */));
+ if (!mLauncher.isInState(EDIT_MODE)) {
+ mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
+ onCompleteCallback == null
+ ? null
+ : forSuccessCallback(
+ () -> callbackList.add(onCompleteCallback)));
+ } else if (onCompleteCallback != null) {
+ forSuccessCallback(() -> callbackList.add(onCompleteCallback));
+ }
mLauncher.getDropTargetBar().onDragEnd();
parent.onDropChild(cell);
return;
@@ -2159,8 +2171,12 @@
}
parent.onDropChild(cell);
- mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,
- onCompleteRunnable == null ? null : forSuccessCallback(onCompleteRunnable));
+ if (!mLauncher.isInState(EDIT_MODE)) {
+ mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,
+ onCompleteRunnable == null ? null : forSuccessCallback(onCompleteRunnable));
+ } else if (onCompleteRunnable != null) {
+ forSuccessCallback(onCompleteRunnable);
+ }
mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId)
.log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);
}
@@ -2734,7 +2750,8 @@
final int screenId = getIdForScreen(cellLayout);
if (!mLauncher.isHotseatLayout(cellLayout)
&& screenId != getScreenIdForPageIndex(mCurrentPage)
- && !mLauncher.isInState(SPRING_LOADED)) {
+ && !mLauncher.isInState(SPRING_LOADED)
+ && !mLauncher.isInState(EDIT_MODE)) {
snapToPage(getPageIndexForScreenId(screenId));
}
@@ -2812,7 +2829,6 @@
} else {
// This is for other drag/drop cases, like dragging from All Apps
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
-
View view;
switch (info.itemType) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 55ab7f1..565d7da 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -59,6 +59,7 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.graphics.Scrim;
import com.android.launcher3.graphics.SysUiScrim;
+import com.android.launcher3.states.EditModeState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DynamicResource;
@@ -212,8 +213,8 @@
PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
StateAnimationConfig config) {
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
- float springLoadedProgress = (state instanceof SpringLoadedState) ? 1.0f : 0f;
-
+ float springLoadedProgress =
+ (state instanceof SpringLoadedState || state instanceof EditModeState) ? 1f : 0f;
propertySetter.setFloat(cl,
CellLayout.SPRING_LOADED_PROGRESS, springLoadedProgress, ZOOM_OUT);
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index a671c6e..30af502 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -45,7 +45,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -53,7 +52,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.function.Predicate;
@@ -97,15 +95,7 @@
StatsLogManager statsLogManager) {
mUserManager = userManager;
mAllApps = allApps;
- boolean cloningChanges = FeatureFlags.ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER.get();
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "matcher flag: " + cloningChanges);
- }
- if (cloningChanges) {
- mMatcher = ofWorkProfileUser(userManager);
- } else {
- mMatcher = mAllApps.mPersonalMatcher.negate();
- }
+ mMatcher = mAllApps.mPersonalMatcher.negate();
mStatsLogManager = statsLogManager;
}
@@ -280,27 +270,4 @@
}
};
}
-
- /**
- * Filter to only display apps in managed profile in work tab.
- */
- private Predicate<ItemInfo> ofWorkProfileUser(UserManager um) {
- return info -> info != null && isManagedProfile(um, info.user.hashCode());
- }
-
-
- private static boolean isManagedProfile(UserManager um, int userId) {
- try {
- // isManagedProfile is a @SystemApi.
- String methodName = "isManagedProfile";
- Method method = um.getClass().getDeclaredMethod(methodName, int.class);
- Object result = method.invoke(um, userId);
- if (result instanceof Boolean) {
- return (boolean) result;
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to call #isManagedProfile via reflection from Launcher");
- }
- return false;
- }
}
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index 714304b..64fd237 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -62,7 +62,8 @@
if (mHighlightedView instanceof BubbleTextView
&& mHighlightedView.getTag() instanceof ItemInfo) {
ItemInfo itemInfo = (ItemInfo) mHighlightedView.getTag();
- return mLauncher.startActivitySafely(mHighlightedView, itemInfo.getIntent(), itemInfo);
+ return mLauncher.startActivitySafely(
+ mHighlightedView, itemInfo.getIntent(), itemInfo) != null;
}
return false;
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2891ce1..621c2ab 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -86,7 +86,7 @@
"ENABLE_ONE_SEARCH_MOTION", ENABLED, "Enables animations in OneSearch.");
public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag(
- 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", TEAMFOOD,
+ 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", DISABLED,
"Enable option to replace decorator-based search result backgrounds with drawables");
public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag(
@@ -142,10 +142,6 @@
"Enables haptics opening/closing All apps");
// TODO(Block 6): Clean up flags
- public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(270393268,
- "WIDGETS_IN_LAUNCHER_PREVIEW", ENABLED,
- "Enables widgets in Launcher preview for the Wallpaper app.");
-
public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
"ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", DISABLED,
"Enables Search box in Taskbar All Apps.");
@@ -211,25 +207,12 @@
"Allows on device search in all apps logging");
// TODO(Block 14): Cleanup flags
- public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(270391641,
- "ASSISTANT_GIVES_LAUNCHER_FOCUS", DISABLED,
- "Allow Launcher to handle nav bar gestures while Assistant is running over it");
-
public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES",
DISABLED, "Sends a notification whenever launcher encounters an uncaught exception.");
- public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag(270395077,
- "FORCE_PERSISTENT_TASKBAR", DISABLED, "Forces taskbar to be persistent, even in gesture"
- + " nav mode and when transient taskbar is enabled.");
-
public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
"ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
- // TODO(Block 15): Clean up flags
- public static final BooleanFlag ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER = getDebugFlag(266177840,
- "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", DISABLED,
- "Removes clone apps from the work profile tab.");
-
// TODO(Block 16): Clean up flags
// When enabled the promise icon is visible in all apps while installation an app.
public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
@@ -314,6 +297,10 @@
"Enables receiving unfold animation events from sysui instead of calculating "
+ "them in launcher process using hinge sensor values.");
+ public static final BooleanFlag ENABLE_WIDGET_TRANSITION_FOR_RESIZING = getDebugFlag(268553314,
+ "ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
+ "Enable widget transition animation when resizing the widgets");
+
public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
"PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
"Enables starting the unfold animation preemptively when unfolding, without"
@@ -404,6 +391,10 @@
public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
"ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching");
+ public static final BooleanFlag ENABLE_KEYBOARD_TASKBAR_TOGGLE = getDebugFlag(281726846,
+ "ENABLE_KEYBOARD_TASKBAR_TOGGLE", ENABLED,
+ "Enables keyboard taskbar stash toggling");
+
// TODO(Block 30): Clean up flags
public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
"USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED,
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index aaa5b1a..da6f446 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -157,7 +158,9 @@
@Override
protected void exitDrag() {
- mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ if (!mActivity.isInState(EDIT_MODE)) {
+ mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ }
}
@Override
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragView.java b/src/com/android/launcher3/dragndrop/LauncherDragView.java
index cc68e2e..4c43865 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragView.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragView.java
@@ -57,7 +57,8 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
setVisibility((finalState == LauncherState.NORMAL
- || finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
+ || finalState == LauncherState.SPRING_LOADED
+ || finalState == LauncherState.EDIT_MODE) ? VISIBLE : INVISIBLE);
}
@Override
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index dd74125..7bdec1c 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -16,6 +16,11 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
+import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
+
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
@@ -29,10 +34,8 @@
import android.os.Process;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -90,11 +93,11 @@
@Override
public WorkspaceItemInfo createWorkspaceItemInfo() {
+ long transitionDuration = (MULTI_SELECT_EDIT_MODE.get() ? EDIT_MODE : SPRING_LOADED)
+ .getTransitionDuration(Launcher.getLauncher(mContext), true /* isToState */);
// Total duration for the drop animation to complete.
long duration = mContext.getResources().getInteger(R.integer.config_dropAnimMaxDuration) +
- LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY +
- LauncherState.SPRING_LOADED.getTransitionDuration(Launcher.getLauncher(mContext),
- true /* isToState */);
+ SPRING_LOADED_EXIT_DELAY + transitionDuration;
// Delay the actual accept() call until the drop animation is complete.
return PinRequestHelper.createWorkspaceItemFromPinItemRequest(
mContext, mRequestSupplier.get(), duration);
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3c31b7a..4ae54e6 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -19,6 +19,7 @@
import static android.text.TextUtils.isEmpty;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
@@ -558,7 +559,7 @@
.inflate(R.layout.user_folder_icon_normalized, null);
}
- private void startAnimation(final AnimatorSet a) {
+ private void addAnimationStartListeners(AnimatorSet a) {
mLauncherDelegate.forEachVisibleWorkspacePage(
visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
@@ -574,7 +575,6 @@
mCurrentAnimator = null;
}
});
- a.start();
}
private void addAnimatorListenerForPage(AnimatorSet a, CellLayout currentCellLayout) {
@@ -734,10 +734,14 @@
mPageIndicator.stopAllAnimations();
+ // b/282158620 because setCurrentPlayTime() below will start animator, we need to register
+ // {@link AnimatorListener} before it so that {@link AnimatorListener#onAnimationStart} can
+ // be called to register mCurrentAnimator, which will be used to cancel animator
+ addAnimationStartListeners(anim);
// Because t=0 has the folder match the folder icon, we can skip the
// first frame and have the same movement one frame earlier.
anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration()));
- startAnimation(anim);
+ anim.start();
// Make sure the folder picks up the last drag move even if the finger doesn't move.
if (mDragController.isDragging()) {
@@ -815,7 +819,8 @@
mIsAnimatingClosed = false;
}
});
- startAnimation(a);
+ addAnimationStartListeners(a);
+ a.start();
}
@Override
@@ -1339,7 +1344,10 @@
mLauncherDelegate.getModelWriter());
}
- launcher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ if (!launcher.isInState(EDIT_MODE)) {
+ launcher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ }
+
if (d.stateAnnouncer != null) {
d.stateAnnouncer.completeAction(R.string.item_moved);
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 05ad57a..2ce6c78 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -265,23 +265,37 @@
Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
play(a, z, mIsOpening ? midDuration : 0, midDuration);
- // Store clip variables
- CellLayout cellLayout = mContent.getCurrentCellLayout();
- boolean folderClipChildren = mFolder.getClipChildren();
- boolean folderClipToPadding = mFolder.getClipToPadding();
- boolean contentClipChildren = mContent.getClipChildren();
- boolean contentClipToPadding = mContent.getClipToPadding();
- boolean cellLayoutClipChildren = cellLayout.getClipChildren();
- boolean cellLayoutClipPadding = cellLayout.getClipToPadding();
-
- mFolder.setClipChildren(false);
- mFolder.setClipToPadding(false);
- mContent.setClipChildren(false);
- mContent.setClipToPadding(false);
- cellLayout.setClipChildren(false);
- cellLayout.setClipToPadding(false);
-
+ // Store clip variables.
+ // Because {@link #onAnimationStart} and {@link #onAnimationEnd} callbacks are sent to
+ // message queue and executed on separate frame, we should save states in
+ // {@link #onAnimationStart} instead of before creating animator, so that cancelling
+ // animation A and restarting animation B allows A to reset states in
+ // {@link #onAnimationEnd} before B reads new UI state from {@link #onAnimationStart}.
a.addListener(new AnimatorListenerAdapter() {
+ private CellLayout mCellLayout;
+ private boolean mFolderClipToPadding;
+ private boolean mContentClipChildren;
+ private boolean mContentClipToPadding;
+ private boolean mCellLayoutClipChildren;
+ private boolean mCellLayoutClipPadding;
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ super.onAnimationStart(animator);
+ mCellLayout = mContent.getCurrentCellLayout();
+ mFolderClipToPadding = mFolder.getClipToPadding();
+ mContentClipChildren = mContent.getClipChildren();
+ mContentClipToPadding = mContent.getClipToPadding();
+ mCellLayoutClipChildren = mCellLayout.getClipChildren();
+ mCellLayoutClipPadding = mCellLayout.getClipToPadding();
+
+ mFolder.setClipToPadding(false);
+ mContent.setClipChildren(false);
+ mContent.setClipToPadding(false);
+ mCellLayout.setClipChildren(false);
+ mCellLayout.setClipToPadding(false);
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
@@ -295,13 +309,11 @@
mFolder.mFooter.setTranslationX(0f);
mFolder.mFolderName.setAlpha(1f);
- mFolder.setClipChildren(folderClipChildren);
- mFolder.setClipToPadding(folderClipToPadding);
- mContent.setClipChildren(contentClipChildren);
- mContent.setClipToPadding(contentClipToPadding);
- cellLayout.setClipChildren(cellLayoutClipChildren);
- cellLayout.setClipToPadding(cellLayoutClipPadding);
-
+ mFolder.setClipToPadding(mFolderClipToPadding);
+ mContent.setClipChildren(mContentClipChildren);
+ mContent.setClipToPadding(mContentClipToPadding);
+ mCellLayout.setClipChildren(mCellLayoutClipChildren);
+ mCellLayout.setClipToPadding(mCellLayoutClipPadding);
}
});
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index b438e86..47677ea 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -105,7 +105,6 @@
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LauncherWidgetHolder;
import com.android.launcher3.widget.LocalColorExtractor;
-import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import com.android.launcher3.widget.util.WidgetSizes;
@@ -281,9 +280,7 @@
} else {
mWallpaperColorResources = null;
}
- mAppWidgetHost = FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()
- ? new LauncherPreviewAppWidgetHost(context)
- : null;
+ mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
}
/** Populate preview and render it. */
@@ -416,19 +413,8 @@
private void inflateAndAddWidgets(
LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
- AppWidgetHostView view;
- if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
- view = mAppWidgetHost.createView(mContext, info.appWidgetId, providerInfo);
- } else {
- view = new NavigableAppWidgetHostView(this) {
- @Override
- protected boolean shouldAllowDirectClick() {
- return false;
- }
- };
- view.setAppWidget(-1, providerInfo);
- view.updateAppWidget(null);
- }
+ AppWidgetHostView view = mAppWidgetHost.createView(
+ mContext, info.appWidgetId, providerInfo);
if (mWallpaperColorResources != null) {
view.setColorResources(mWallpaperColorResources);
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 8f0b8ec..e89c0c5 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -51,7 +51,9 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.GridSizeMigrationUtil;
+import com.android.launcher3.model.LauncherBinder;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.provider.LauncherDbUtils;
@@ -226,12 +228,14 @@
LauncherAppState.getInstance(previewContext)
.getModel().getModelDbController().clearEmptyDbFlag();
+ BgDataModel bgModel = new BgDataModel();
new LoaderTask(
LauncherAppState.getInstance(previewContext),
/* bgAllAppsList= */ null,
- new BgDataModel(),
+ bgModel,
LauncherAppState.getInstance(previewContext).getModel().getModelDelegate(),
- /* results= */ null) {
+ new LauncherBinder(LauncherAppState.getInstance(previewContext), bgModel,
+ /* bgAllAppsList= */ null, new Callbacks[0])) {
@Override
public void run() {
diff --git a/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java b/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java
index a6c897f..408a5a0 100644
--- a/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java
+++ b/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java
@@ -17,6 +17,7 @@
import static android.app.Activity.DEFAULT_KEYS_SEARCH_LOCAL;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import android.app.Activity;
@@ -114,7 +115,7 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- if (toState != SPRING_LOADED) {
+ if (toState != SPRING_LOADED && toState != EDIT_MODE) {
close(false);
}
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index d4eded5..1a8cf24 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -51,6 +51,7 @@
import android.util.Log;
import android.util.LongSparseArray;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
@@ -118,6 +119,7 @@
private static final boolean DEBUG = true;
+ @NonNull
protected final LauncherAppState mApp;
private final AllAppsList mBgAllAppsList;
protected final BgDataModel mBgDataModel;
@@ -125,6 +127,7 @@
private FirstScreenBroadcast mFirstScreenBroadcast;
+ @NonNull
private final LauncherBinder mLauncherBinder;
private final LauncherApps mLauncherApps;
@@ -145,11 +148,11 @@
private boolean mItemsDeleted = false;
private String mDbName;
- public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
- ModelDelegate modelDelegate, LauncherBinder launcherBinder) {
+ public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
+ ModelDelegate modelDelegate, @NonNull LauncherBinder launcherBinder) {
mApp = app;
mBgAllAppsList = bgAllAppsList;
- mBgDataModel = dataModel;
+ mBgDataModel = bgModel;
mModelDelegate = modelDelegate;
mLauncherBinder = launcherBinder;
diff --git a/src/com/android/launcher3/states/EditModeState.kt b/src/com/android/launcher3/states/EditModeState.kt
new file mode 100644
index 0000000..aafaaa0
--- /dev/null
+++ b/src/com/android/launcher3/states/EditModeState.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.launcher3.states
+
+import android.content.Context
+import com.android.launcher3.Launcher
+import com.android.launcher3.LauncherState
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.views.ActivityContext
+
+/** Definition for Edit Mode state used for home gardening multi-select */
+class EditModeState(id: Int) : LauncherState(id, StatsLogManager.LAUNCHER_STATE_HOME, STATE_FLAGS) {
+
+ companion object {
+ private val STATE_FLAGS =
+ (FLAG_MULTI_PAGE or
+ FLAG_WORKSPACE_INACCESSIBLE or
+ FLAG_DISABLE_RESTORE or
+ FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED or
+ FLAG_WORKSPACE_HAS_BACKGROUNDS)
+ }
+
+ override fun <T> getTransitionDuration(context: T, isToState: Boolean): Int where
+ T : Context?,
+ T : ActivityContext? {
+ return 150
+ }
+
+ override fun <T> getDepthUnchecked(context: T): Float where T : Context?, T : ActivityContext? {
+ return 0.5f
+ }
+
+ override fun getWorkspaceScaleAndTranslation(launcher: Launcher): ScaleAndTranslation {
+ val scale = launcher.deviceProfile.getWorkspaceSpringLoadScale(launcher)
+ return ScaleAndTranslation(scale, 0f, 0f)
+ }
+
+ override fun getHotseatScaleAndTranslation(launcher: Launcher): ScaleAndTranslation {
+ val scale = launcher.deviceProfile.getWorkspaceSpringLoadScale(launcher)
+ return ScaleAndTranslation(scale, 0f, 0f)
+ }
+
+ override fun getWorkspaceBackgroundAlpha(launcher: Launcher): Float {
+ return 0.2f
+ }
+
+ override fun onLeavingState(launcher: Launcher?, toState: LauncherState?) {
+ // cleanup any changes to workspace
+ }
+}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 7db7b0d..9cba19d 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -19,6 +19,7 @@
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED;
@@ -58,7 +59,11 @@
}
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
- if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
+ if (!launcher.isInState(NORMAL)
+ && !launcher.isInState(OVERVIEW)
+ && !launcher.isInState(EDIT_MODE)) {
+ return false;
+ }
if (!(v.getTag() instanceof ItemInfo)) return false;
launcher.setWaitingForResult(null);
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index badcd35..6a4e528 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -136,16 +136,19 @@
if (mDestroyed) {
Log.e(TAG, "Static object access with a destroyed context");
}
- if (!mAllowedObjects.contains(object)) {
- throw new IllegalStateException(
- "Leaking unknown objects " + object + " " + provider);
- }
+
T t = (T) mObjectMap.get(object);
if (t != null) {
return t;
}
if (Looper.myLooper() == Looper.getMainLooper()) {
t = createObject(provider);
+ // Check if we've explicitly allowed the object or if it's a SafeCloseable,
+ // it will get destroyed in onDestroy()
+ if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
+ throw new IllegalStateException(
+ "Leaking unknown objects " + object + " " + provider + " " + t);
+ }
mObjectMap.put(object, t);
mOrderedObjects.add(t);
return t;
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 31b1934..515a2d8 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.views;
+import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
+
+import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
@@ -45,7 +48,6 @@
import android.view.WindowInsetsController;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
-import android.window.SplashScreen;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -289,27 +291,27 @@
}
}
-
/**
* Sends a pending intent animating from a view.
*
* @param v View to animate.
* @param intent The pending intent being launched.
* @param item Item associated with the view.
- * @return {@code true} if the intent is sent successfully.
+ * @return RunnableList for listening for animation finish if the activity was properly
+ * or started, {@code null} if the launch finished
*/
- default boolean sendPendingIntentWithAnimation(
+ default RunnableList sendPendingIntentWithAnimation(
@NonNull View v, PendingIntent intent, @Nullable ItemInfo item) {
- Bundle optsBundle = getActivityLaunchOptions(v, item).toBundle();
+ ActivityOptionsWrapper options = getActivityLaunchOptions(v, item);
try {
- intent.send(null, 0, null, null, null, null, optsBundle);
- return true;
+ intent.send(null, 0, null, null, null, null, options.toBundle());
+ return options.onEndCallback;
} catch (PendingIntent.CanceledException e) {
Toast.makeText(v.getContext(),
v.getContext().getResources().getText(R.string.shortcut_not_available),
Toast.LENGTH_SHORT).show();
}
- return false;
+ return null;
}
/**
@@ -318,28 +320,23 @@
* @param v View starting the activity.
* @param intent Base intent being launched.
* @param item Item associated with the view.
- * @return {@code true} if the activity starts successfully.
+ * @return RunnableList for listening for animation finish if the activity was properly
+ * or started, {@code null} if the launch finished
*/
- default boolean startActivitySafely(
+ default RunnableList startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
Preconditions.assertUIThread();
Context context = (Context) this;
if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
- return false;
+ return null;
}
- Bundle optsBundle = null;
- if (v != null) {
- optsBundle = getActivityLaunchOptions(v, item).toBundle();
- } else if (android.os.Build.VERSION.SDK_INT >= 33
- && item != null
- && item.animationType == LauncherSettings.Animation.DEFAULT_NO_ICON) {
- optsBundle = ActivityOptions.makeBasic()
- .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR).toBundle();
- }
+ ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
+ : makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
+ ? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
UserHandle user = item == null ? null : item.user;
-
+ Bundle optsBundle = options.toBundle();
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
@@ -364,12 +361,12 @@
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
logAppLaunch(getStatsLogManager(), item, instanceId);
}
- return true;
+ return options.onEndCallback;
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
- return false;
+ return null;
}
/** Returns {@code true} if an app launch is blocked due to safe mode. */
@@ -417,6 +414,17 @@
}
/**
+ * Creates a default activity option and we do not want association with any launcher element.
+ */
+ default ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ if (Utilities.ATLEAST_T) {
+ options.setSplashScreenStyle(splashScreenStyle);
+ }
+ return new ActivityOptionsWrapper(options, new RunnableList());
+ }
+
+ /**
* Safely launches an intent for a shortcut.
*
* @param intent Intent to start.
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 64ad390..4641e31 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -17,6 +17,7 @@
import static androidx.core.content.ContextCompat.getColorStateList;
+import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -222,6 +223,8 @@
}
private static boolean enterHomeGardening(View view) {
+ Launcher launcher = Launcher.getLauncher(view.getContext());
+ launcher.getStateManager().goToState(EDIT_MODE);
return true;
}
@@ -281,7 +284,7 @@
if (!TextUtils.isEmpty(pickerPackage)) {
intent.setPackage(pickerPackage);
}
- return launcher.startActivitySafely(v, intent, placeholderInfo(intent));
+ return launcher.startActivitySafely(v, intent, placeholderInfo(intent)) != null;
}
static WorkspaceItemInfo placeholderInfo(Intent intent) {
diff --git a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
index 971fd9b..ac0a166 100644
--- a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
+++ b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
@@ -25,6 +25,7 @@
import com.android.launcher3.R
import com.android.launcher3.util.ResourceHelper
import java.io.IOException
+import kotlin.math.roundToInt
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
@@ -159,6 +160,77 @@
}
}
}
+
+ /**
+ * Returns the CalculatedWorkspaceSpec for width, based on the available width and the
+ * WorkspaceSpecs.
+ */
+ fun getCalculatedWidthSpec(columns: Int, availableWidth: Int): CalculatedWorkspaceSpec {
+ val widthSpec = workspaceWidthSpecList.first { availableWidth <= it.maxAvailableSize }
+
+ return CalculatedWorkspaceSpec(availableWidth, columns, widthSpec)
+ }
+
+ /**
+ * Returns the CalculatedWorkspaceSpec for height, based on the available height and the
+ * WorkspaceSpecs.
+ */
+ fun getCalculatedHeightSpec(rows: Int, availableHeight: Int): CalculatedWorkspaceSpec {
+ val heightSpec = workspaceHeightSpecList.first { availableHeight <= it.maxAvailableSize }
+
+ return CalculatedWorkspaceSpec(availableHeight, rows, heightSpec)
+ }
+}
+
+class CalculatedWorkspaceSpec(
+ val availableSpace: Int,
+ val cells: Int,
+ val workspaceSpec: WorkspaceSpec
+) {
+ var startPaddingPx: Int = 0
+ private set
+ var endPaddingPx: Int = 0
+ private set
+ var gutterPx: Int = 0
+ private set
+ var cellSizePx: Int = 0
+ private set
+ init {
+ // Calculate all fixed size first
+ if (workspaceSpec.startPadding.fixedSize > 0)
+ startPaddingPx = workspaceSpec.startPadding.fixedSize.roundToInt()
+ if (workspaceSpec.endPadding.fixedSize > 0)
+ endPaddingPx = workspaceSpec.endPadding.fixedSize.roundToInt()
+ if (workspaceSpec.gutter.fixedSize > 0)
+ gutterPx = workspaceSpec.gutter.fixedSize.roundToInt()
+ if (workspaceSpec.cellSize.fixedSize > 0)
+ cellSizePx = workspaceSpec.cellSize.fixedSize.roundToInt()
+
+ // Calculate all available space next
+ if (workspaceSpec.startPadding.ofAvailableSpace > 0)
+ startPaddingPx =
+ (workspaceSpec.startPadding.ofAvailableSpace * availableSpace).roundToInt()
+ if (workspaceSpec.endPadding.ofAvailableSpace > 0)
+ endPaddingPx = (workspaceSpec.endPadding.ofAvailableSpace * availableSpace).roundToInt()
+ if (workspaceSpec.gutter.ofAvailableSpace > 0)
+ gutterPx = (workspaceSpec.gutter.ofAvailableSpace * availableSpace).roundToInt()
+ if (workspaceSpec.cellSize.ofAvailableSpace > 0)
+ cellSizePx = (workspaceSpec.cellSize.ofAvailableSpace * availableSpace).roundToInt()
+
+ // Calculate remainder space last
+ val gutters = cells - 1
+ val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
+ val remainderSpace = availableSpace - usedSpace
+ if (workspaceSpec.startPadding.ofRemainderSpace > 0)
+ startPaddingPx =
+ (workspaceSpec.startPadding.ofRemainderSpace * remainderSpace).roundToInt()
+ if (workspaceSpec.endPadding.ofRemainderSpace > 0)
+ endPaddingPx = (workspaceSpec.endPadding.ofRemainderSpace * remainderSpace).roundToInt()
+ if (workspaceSpec.gutter.ofRemainderSpace > 0)
+ gutterPx = (workspaceSpec.gutter.ofRemainderSpace * remainderSpace).roundToInt()
+ if (workspaceSpec.cellSize.ofRemainderSpace > 0)
+ cellSizePx = (workspaceSpec.cellSize.ofRemainderSpace * remainderSpace).roundToInt()
+ }
}
data class WorkspaceSpec(
@@ -220,7 +292,7 @@
fun isValid(): Boolean {
// All attributes are empty
- if (fixedSize <= 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
+ if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
return false
}
diff --git a/tests/Android.bp b/tests/Android.bp
index fa0cdf2..e7f4084 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -51,6 +51,7 @@
"src/com/android/launcher3/util/WidgetUtils.java",
"src/com/android/launcher3/util/rule/FailureWatcher.java",
"src/com/android/launcher3/util/rule/LauncherActivityRule.java",
+ "src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
"src/com/android/launcher3/util/rule/SamplerRule.java",
"src/com/android/launcher3/util/rule/ScreenRecordRule.java",
"src/com/android/launcher3/util/rule/ShellCommandRule.java",
@@ -132,4 +133,4 @@
manifest: "shared/AndroidManifest.xml",
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
- }
\ No newline at end of file
+ }
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 91a3e48..1f97314 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -15,43 +15,45 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <!-- 584 grid height -->
<workspaceSpec
launcher:specType="height"
- launcher:maxAvailableSize="648dp">
- <startPadding
- launcher:ofAvailableSpace="0.0125" />
- <endPadding
- launcher:ofAvailableSpace="0.05" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
+ launcher:maxAvailableSize="584dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="32dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofAvailableSpace="0.15808" />
+ </workspaceSpec>
+
+ <!-- 584 grid height + 28 remainder space -->
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="612dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
</workspaceSpec>
<workspaceSpec
launcher:specType="height"
launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofAvailableSpace="0.0306" />
- <endPadding
- launcher:ofAvailableSpace="0.068" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
+ <startPadding launcher:fixedSize="8dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
</workspaceSpec>
+ <!-- TODO(b/241386436): other specs here for height ... -->
+
<!-- Width spec is always the same -->
<workspaceSpec
launcher:specType="width"
launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofRemainderSpace="0.21436227" />
- <endPadding
- launcher:ofRemainderSpace="0.21436227" />
- <gutter
- launcher:ofRemainderSpace="0.11425509" />
- <cellSize
- launcher:fixedSize="120dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
</workspaceSpec>
+
</workspaceSpecs>
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 601b07e..2b67cdd 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -36,6 +36,7 @@
public static final int HINT_STATE_ORDINAL = 7;
public static final int HINT_STATE_TWO_BUTTON_ORDINAL = 8;
public static final int OVERVIEW_SPLIT_SELECT_ORDINAL = 9;
+ public static final int EDIT_MODE_STATE_ORDINAL = 10;
public static final String TAPL_EVENTS_TAG = "TaplEvents";
public static final String SEQUENCE_MAIN = "Main";
public static final String SEQUENCE_TIS = "TIS";
@@ -63,6 +64,8 @@
return "Hint2Button";
case OVERVIEW_SPLIT_SELECT_ORDINAL:
return "OverviewSplitSelect";
+ case EDIT_MODE_STATE_ORDINAL:
+ return "EditMode";
default:
return "Unknown";
}
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 01f494b..3de4d55 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -66,7 +66,7 @@
class DeviceSpec(
val naturalSize: Pair<Int, Int>,
- val densityDpi: Int,
+ var densityDpi: Int,
val statusBarNaturalPx: Int,
val statusBarRotatedPx: Int,
val gesturePx: Int,
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 3141c7b..d7c4ae3 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -72,6 +72,7 @@
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.rule.ViewCaptureRule;
import org.junit.After;
import org.junit.Assert;
@@ -215,14 +216,15 @@
}
protected TestRule getRulesInsideActivityMonitor() {
+ final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
final RuleChain inner = RuleChain
.outerRule(new PortraitLandscapeRunner(this))
- .around(new FailureWatcher(mDevice, mLauncher));
+ .around(viewCaptureRule)
+ .around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()));
return TestHelpers.isInLauncherProcess()
- ? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher())
- .around(inner) :
- inner;
+ ? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
+ : inner;
}
@Rule
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 51facf4..19e7b13 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -7,8 +7,12 @@
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.uiautomator.UiDevice;
+import com.android.app.viewcapture.ViewCapture;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -29,10 +33,14 @@
private static boolean sSavedBugreport = false;
final private UiDevice mDevice;
private final LauncherInstrumentation mLauncher;
+ @NonNull
+ private final ViewCapture mViewCapture;
- public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) {
+ public FailureWatcher(UiDevice device, LauncherInstrumentation launcher,
+ @NonNull ViewCapture viewCapture) {
mDevice = device;
mLauncher = launcher;
+ mViewCapture = viewCapture;
}
@Override
@@ -82,7 +90,7 @@
@Override
protected void failed(Throwable e, Description description) {
- onError(mLauncher, description, e);
+ onError(mLauncher, description, e, mViewCapture);
}
static File diagFile(Description description, String prefix, String ext) {
@@ -93,8 +101,12 @@
public static void onError(LauncherInstrumentation launcher, Description description,
Throwable e) {
- final UiDevice device = launcher.getDevice();
- if (device == null) return;
+ onError(launcher, description, e, null);
+ }
+
+ private static void onError(LauncherInstrumentation launcher, Description description,
+ Throwable e, @Nullable ViewCapture viewCapture) {
+
final File sceenshot = diagFile(description, "TestScreenshot", "png");
final File hierarchy = diagFile(description, "Hierarchy", "zip");
@@ -109,13 +121,20 @@
out.putNextEntry(new ZipEntry("visible_windows.zip"));
dumpCommand("cmd window dump-visible-window-views", out);
out.closeEntry();
- } catch (IOException ex) {
+
+ if (viewCapture != null) {
+ out.putNextEntry(new ZipEntry("FS/data/misc/wmtrace/failed_test.vc"));
+ viewCapture.dumpTo(out, ApplicationProvider.getApplicationContext());
+ out.closeEntry();
+ }
+ } catch (Exception ignored) {
}
Log.e(TAG, "Failed test " + description.getMethodName()
+ ",\nscreenshot will be saved to " + sceenshot
+ ",\nUI dump at: " + hierarchy
+ " (use go/web-hv to open the dump file)", e);
+ final UiDevice device = launcher.getDevice();
device.takeScreenshot(sceenshot);
// Dump accessibility hierarchy
diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
index 2093682..e9a52f8 100644
--- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
@@ -56,4 +56,4 @@
return launcher.getWorkspace().getFirstMatch(op) != null;
};
}
-}
+}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
index 1dbba6a..2eedec3 100644
--- a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
@@ -102,4 +102,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
new file mode 100644
index 0000000..e4713b2
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.launcher3.util.rule
+
+import android.app.Activity
+import android.app.Application
+import android.media.permission.SafeCloseable
+import android.os.Bundle
+import androidx.test.core.app.ApplicationProvider
+import com.android.app.viewcapture.SimpleViewCapture
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * This JUnit TestRule registers a listener for activity lifecycle events to attach a ViewCapture
+ * instance that other test rules use to dump the timelapse hierarchy upon an error during a test.
+ *
+ * This rule will not work in OOP tests that don't have access to the activity under test.
+ */
+class ViewCaptureRule : TestRule {
+ val viewCapture = SimpleViewCapture("test-view-capture")
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ val windowListenerCloseables = mutableListOf<SafeCloseable>()
+
+ val lifecycleCallbacks =
+ object : ActivityLifecycleCallbacksAdapter {
+ override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
+ super.onActivityCreated(activity, bundle)
+ windowListenerCloseables.add(
+ viewCapture.startCapture(
+ activity.window.decorView,
+ "${description.testClass?.simpleName}.${description.methodName}"
+ )
+ )
+ }
+
+ override fun onActivityDestroyed(activity: Activity) {
+ super.onActivityDestroyed(activity)
+ viewCapture.stopCapture(activity.window.decorView)
+ }
+ }
+
+ val application = ApplicationProvider.getApplicationContext<Application>()
+ application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
+
+ try {
+ base.evaluate()
+ } finally {
+ application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
+
+ // 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)
+ }
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt b/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt
new file mode 100644
index 0000000..7f03ba2
--- /dev/null
+++ b/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.launcher3.workspace
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculatedWorkspaceSpecTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+
+ /**
+ * This test tests:
+ * - (height spec) gets the correct breakpoint from the XML - skips the first 2 breakpoints
+ * - (height spec) do the correct calculations for available space and fixed size
+ * - (width spec) do the correct calculations for remainder space and fixed size
+ */
+ @Test
+ fun normalPhone_returnsThirdBreakpointSpec() {
+ val deviceSpec = deviceSpecs["phone"]!!
+ initializeVarsForPhone(deviceSpec)
+
+ val availableWidth = deviceSpec.naturalSize.first
+ // Hotseat size is roughly 495px on a real device,
+ // it doesn't need to be precise on unit tests
+ val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
+
+ val workspaceSpecs =
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+ val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
+ val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+
+ assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
+ assertThat(widthSpec.cells).isEqualTo(4)
+ assertThat(widthSpec.startPaddingPx).isEqualTo(58)
+ assertThat(widthSpec.endPaddingPx).isEqualTo(58)
+ assertThat(widthSpec.gutterPx).isEqualTo(42)
+ assertThat(widthSpec.cellSizePx).isEqualTo(210)
+
+ assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
+ assertThat(heightSpec.cells).isEqualTo(5)
+ assertThat(heightSpec.startPaddingPx).isEqualTo(21)
+ assertThat(heightSpec.endPaddingPx).isEqualTo(233)
+ assertThat(heightSpec.gutterPx).isEqualTo(42)
+ assertThat(heightSpec.cellSizePx).isEqualTo(273)
+ }
+
+ /**
+ * This test tests:
+ * - (height spec) gets the correct breakpoint from the XML - use the first breakpoint
+ * - (height spec) do the correct calculations for remainder space and fixed size
+ * - (width spec) do the correct calculations for remainder space and fixed size
+ */
+ @Test
+ fun smallPhone_returnsFirstBreakpointSpec() {
+ val deviceSpec = deviceSpecs["phone"]!!
+ deviceSpec.densityDpi = 540 // larger display size
+ initializeVarsForPhone(deviceSpec)
+
+ val availableWidth = deviceSpec.naturalSize.first
+ // Hotseat size is roughly 640px on a real device,
+ // it doesn't need to be precise on unit tests
+ val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
+
+ val workspaceSpecs =
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+ val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
+ val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+
+ assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
+ assertThat(widthSpec.cells).isEqualTo(4)
+ assertThat(widthSpec.startPaddingPx).isEqualTo(74)
+ assertThat(widthSpec.endPaddingPx).isEqualTo(74)
+ assertThat(widthSpec.gutterPx).isEqualTo(54)
+ assertThat(widthSpec.cellSizePx).isEqualTo(193)
+
+ assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
+ assertThat(heightSpec.cells).isEqualTo(5)
+ assertThat(heightSpec.startPaddingPx).isEqualTo(0)
+ assertThat(heightSpec.endPaddingPx).isEqualTo(108)
+ assertThat(heightSpec.gutterPx).isEqualTo(54)
+ assertThat(heightSpec.cellSizePx).isEqualTo(260)
+ }
+}
diff --git a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
index 0fd8a54..9cd0a2e 100644
--- a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
@@ -42,43 +42,62 @@
fun parseValidFile() {
val workspaceSpecs =
WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
- assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(2)
+ assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(3)
assertThat(workspaceSpecs.workspaceHeightSpecList[0].toString())
.isEqualTo(
"WorkspaceSpec(" +
- "maxAvailableSize=1701, " +
+ "maxAvailableSize=1533, " +
"specType=HEIGHT, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
- "ofAvailableSpace=0.0125, " +
+ "ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0), " +
- "endPadding=SizeSpec(fixedSize=0.0, " +
- "ofAvailableSpace=0.05, " +
+ "endPadding=SizeSpec(fixedSize=84.0, " +
+ "ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0), " +
"gutter=SizeSpec(fixedSize=42.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0), " +
"cellSize=SizeSpec(fixedSize=0.0, " +
- "ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.2)" +
+ "ofAvailableSpace=0.15808, " +
+ "ofRemainderSpace=0.0)" +
")"
)
assertThat(workspaceSpecs.workspaceHeightSpecList[1].toString())
.isEqualTo(
"WorkspaceSpec(" +
- "maxAvailableSize=26247, " +
+ "maxAvailableSize=1607, " +
"specType=HEIGHT, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
- "ofAvailableSpace=0.0306, " +
+ "ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0), " +
"endPadding=SizeSpec(fixedSize=0.0, " +
- "ofAvailableSpace=0.068, " +
- "ofRemainderSpace=0.0), " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=1.0), " +
"gutter=SizeSpec(fixedSize=42.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0), " +
- "cellSize=SizeSpec(fixedSize=0.0, " +
+ "cellSize=SizeSpec(fixedSize=273.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.2)" +
+ "ofRemainderSpace=0.0)" +
+ ")"
+ )
+ assertThat(workspaceSpecs.workspaceHeightSpecList[2].toString())
+ .isEqualTo(
+ "WorkspaceSpec(" +
+ "maxAvailableSize=26247, " +
+ "specType=HEIGHT, " +
+ "startPadding=SizeSpec(fixedSize=21.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "endPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=1.0), " +
+ "gutter=SizeSpec(fixedSize=42.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "cellSize=SizeSpec(fixedSize=273.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0)" +
")"
)
assertThat(workspaceSpecs.workspaceWidthSpecList.size).isEqualTo(1)
@@ -87,18 +106,18 @@
"WorkspaceSpec(" +
"maxAvailableSize=26247, " +
"specType=WIDTH, " +
- "startPadding=SizeSpec(fixedSize=0.0, " +
+ "startPadding=SizeSpec(fixedSize=58.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.21436226), " +
- "endPadding=SizeSpec(fixedSize=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "endPadding=SizeSpec(fixedSize=58.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.21436226), " +
- "gutter=SizeSpec(fixedSize=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "gutter=SizeSpec(fixedSize=42.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.11425509), " +
- "cellSize=SizeSpec(fixedSize=315.0, " +
+ "ofRemainderSpace=0.0), " +
+ "cellSize=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.0)" +
+ "ofRemainderSpace=0.25)" +
")"
)
}