Merge "Add logging for adding pending icons to the workspace." into sc-dev
diff --git a/Android.bp b/Android.bp
index 92cc36b..e30d22f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,6 +44,7 @@
"src/com/android/launcher3/ResourceUtils.java",
"src/com/android/launcher3/testing/TestProtocol.java",
],
+ resource_dirs: [ ],
manifest: "tests/tapl/AndroidManifest.xml",
platform_apis: true,
}
@@ -178,7 +179,6 @@
srcs: [ ],
resource_dirs: [
"quickstep/res",
- "quickstep/overview_ui_overrides/res",
],
static_libs: [
"Launcher3ResLib",
diff --git a/Android.mk b/Android.mk
index 89870a6..54a80b7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,9 +78,7 @@
$(call all-java-files-under, quickstep/src) \
$(call all-java-files-under, src_shortcuts_overrides)
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/quickstep/res \
- $(LOCAL_PATH)/quickstep/overview_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
LOCAL_PROGUARD_ENABLED := disabled
@@ -109,9 +107,7 @@
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/quickstep/res \
- $(LOCAL_PATH)/quickstep/overview_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
LOCAL_FULL_LIBS_MANIFEST_FILES := \
$(LOCAL_PATH)/quickstep/AndroidManifest-launcher.xml \
@@ -148,10 +144,9 @@
$(call all-java-files-under, go/quickstep/src)
LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/quickstep/res \
- $(LOCAL_PATH)/go/res \
$(LOCAL_PATH)/go/quickstep/res \
- $(LOCAL_PATH)/go/quickstep/overview_ui_overrides/res
+ $(LOCAL_PATH)/go/res \
+ $(LOCAL_PATH)/quickstep/res
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PROGUARD_ENABLED := full
diff --git a/go/quickstep/overview_ui_overrides/res/values/config.xml b/go/quickstep/overview_ui_overrides/res/values/config.xml
deleted file mode 100644
index ec21a01..0000000
--- a/go/quickstep/overview_ui_overrides/res/values/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2021 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.
-*/
--->
-<resources>
- <string name="task_overlay_factory_class" translatable="false">
- com.android.quickstep.TaskOverlayFactoryGo</string>
-</resources>
\ No newline at end of file
diff --git a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
similarity index 95%
rename from go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
rename to go/quickstep/res/layout/overview_actions_container.xml
index e6af848..866eac6 100644
--- a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -14,11 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+ loaded at runtime. -->
<com.android.quickstep.views.GoOverviewActionsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/action_buttons"
diff --git a/go/quickstep/res/values/config.xml b/go/quickstep/res/values/config.xml
index a21381c..402bf9a 100644
--- a/go/quickstep/res/values/config.xml
+++ b/go/quickstep/res/values/config.xml
@@ -21,4 +21,6 @@
<!-- Feature Flags -->
<bool name="enable_niu_actions">true</bool>
+
+ <string name="task_overlay_factory_class" translatable="false">com.android.quickstep.TaskOverlayFactoryGo</string>
</resources>
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 872f168..350e0d1 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -20,25 +20,17 @@
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
import android.annotation.SuppressLint;
-import android.app.ActivityTaskManager;
-import android.app.IAssistDataReceiver;
import android.app.assist.AssistContent;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
import android.graphics.Matrix;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.text.TextUtils;
-import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
+import com.android.quickstep.util.AssistContentRequester;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.systemui.shared.recents.model.Task;
@@ -53,7 +45,6 @@
public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH";
public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos";
public static final String ACTIONS_URL = "niu_actions_app_url";
- private static final String ASSIST_KEY_CONTENT = "content";
private static final String TAG = "TaskOverlayFactoryGo";
// Empty constructor required for ResourceBasedOverride
@@ -72,13 +63,10 @@
*/
public static final class TaskOverlayGo<T extends OverviewActionsView> extends TaskOverlay {
private String mNIUPackageName;
- private int mTaskId;
- private Bundle mAssistData;
- private final Handler mMainThreadHandler;
+ private String mWebUrl;
private TaskOverlayGo(TaskThumbnailView taskThumbnailView) {
super(taskThumbnailView);
- mMainThreadHandler = new Handler(Looper.getMainLooper());
}
/**
@@ -99,28 +87,23 @@
boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
- mTaskId = task.key.id;
- AssistDataReceiverImpl receiver = new AssistDataReceiverImpl();
- receiver.setOverlay(this);
-
- try {
- ActivityTaskManager.getService().requestAssistDataForTask(receiver, mTaskId,
- mApplicationContext.getPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to request AssistData");
- }
+ int taskId = task.key.id;
+ AssistContentRequester contentRequester =
+ new AssistContentRequester(mApplicationContext);
+ contentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
}
- /**
- * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's
- * AssistDataRequester
- */
- public void onAssistDataReceived(Bundle data) {
- mMainThreadHandler.post(() -> {
- if (data != null) {
- mAssistData = data;
- }
- });
+ /** Provide Assist Content to the overlay. */
+ @VisibleForTesting
+ public void onAssistContentReceived(AssistContent assistContent) {
+ mWebUrl = assistContent.getWebUri() != null
+ ? assistContent.getWebUri().toString() : null;
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ mWebUrl = null;
}
/**
@@ -139,12 +122,8 @@
.setPackage(mNIUPackageName)
.putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos());
- if (mAssistData != null) {
- final AssistContent content = mAssistData.getParcelable(ASSIST_KEY_CONTENT);
- Uri webUri = (content == null) ? null : content.getWebUri();
- if (webUri != null) {
- intent.putExtra(ACTIONS_URL, webUri.toString());
- }
+ if (mWebUrl != null) {
+ intent.putExtra(ACTIONS_URL, mWebUrl);
}
return intent;
@@ -191,26 +170,6 @@
}
/**
- * Basic AssistDataReceiver. This is passed to ActivityTaskManagerService, which then requests
- * the data.
- */
- private static final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
- private TaskOverlayGo mOverlay;
-
- public void setOverlay(TaskOverlayGo overlay) {
- mOverlay = overlay;
- }
-
- @Override
- public void onHandleAssistData(Bundle data) {
- mOverlay.onAssistDataReceived(data);
- }
-
- @Override
- public void onHandleAssistScreenshot(Bitmap screenshot) {}
- }
-
- /**
* Callbacks the Ui can generate. This is the only way for a Ui to call methods on the
* controller.
*/
diff --git a/quickstep/overview_ui_overrides/res/values/config.xml b/quickstep/overview_ui_overrides/res/values/config.xml
deleted file mode 100644
index 0f09439..0000000
--- a/quickstep/overview_ui_overrides/res/values/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<resources>
- <string name="task_overlay_factory_class" translatable="false"/>
-</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/REMOVED.txt b/quickstep/recents_ui_overrides/src/REMOVED.txt
deleted file mode 100644
index c3a3eaf..0000000
--- a/quickstep/recents_ui_overrides/src/REMOVED.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Temp file to prevent build breakage.
-Will be removed in followup cl.
\ No newline at end of file
diff --git a/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
similarity index 93%
rename from quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
rename to quickstep/res/layout/overview_actions_container.xml
index 1da25e7..b652252 100644
--- a/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -14,10 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+ loaded at runtime. -->
<com.android.quickstep.views.OverviewActionsView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/action_buttons"
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index c61610a..1ee726e 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -21,5 +21,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/recents_clear_all"
- android:textColor="?attr/workspaceTextColor"
+ android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 394e880..d7bcd9e 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -19,8 +19,7 @@
android:id="@+id/split_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/split_placeholder_size"
- android:background="@android:color/white"
- android:alpha=".8"
+ android:background="@android:color/darker_gray"
android:visibility="gone" />
<com.android.quickstep.views.LauncherRecentsView
@@ -30,7 +29,6 @@
android:accessibilityPaneTitle="@string/accessibility_recent_apps"
android:clipChildren="false"
android:clipToPadding="false"
- android:theme="@style/HomeScreenElementTheme"
android:visibility="invisible" />
<include
diff --git a/quickstep/res/layout/scrim_view.xml b/quickstep/res/layout/scrim_view.xml
index 2cc37f9..3f2daf1 100644
--- a/quickstep/res/layout/scrim_view.xml
+++ b/quickstep/res/layout/scrim_view.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.views.ShelfScrimView
+<com.android.quickstep.views.AllAppsScrimView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index be66104..b2ff770 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -15,6 +15,7 @@
-->
<resources>
<string name="overscroll_plugin_factory_class" translatable="false" />
+ <string name="task_overlay_factory_class" translatable="false"/>
<!-- Activities which block home gesture -->
<string-array name="gesture_blocking_activities" translatable="false">
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3036341..3e6c78f 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -36,6 +36,7 @@
<dimen name="overview_grid_bottom_margin">90dp</dimen>
<dimen name="overview_grid_side_margin">54dp</dimen>
<dimen name="overview_grid_row_spacing">42dp</dimen>
+ <dimen name="overview_grid_focus_vertical_margin">130dp</dimen>
<dimen name="split_placeholder_size">110dp</dimen>
<dimen name="recents_page_spacing">16dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 0764bb3..2a06830 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -59,7 +59,7 @@
<string name="all_apps_prediction_tip">Your predicted apps</string>
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
- <string name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+ <string name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
<!-- Hotseat educational strings for users who don't qualify for migration -->
<string name="hotseat_edu_title_migrate">Get app suggestions on the bottom row of your Home screen</string>
@@ -91,70 +91,61 @@
<!-- content description for hotseat items -->
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
- <!-- primary educational text shown for first time search users -->
- <string name="search_edu_primary">Search your phone for apps, people, settings and more!</string>
- <!-- secondary educational text shown for first time search users -->
- <string name="search_edu_secondary">Tap keyboard search button to launch the first search
- result.</string>
-
- <!-- Dismiss button string for search education view -->
- <string name="search_edu_dismiss">Got it.</string>
-
- <!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
- <string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
- <!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
- <string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge" translatable="false">Start at the right edge and swipe toward the middle</string>
- <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
- <string name="back_gesture_feedback_swipe_too_far_from_right_edge" translatable="false">Make sure you swipe from the far right edge</string>
- <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is cancelled. [CHAR LIMIT=100] -->
- <string name="back_gesture_feedback_cancelled_right_edge" translatable="false">Make sure you swipe straight to the left and let go</string>
-
- <!-- Title shown during interactive part of Back gesture tutorial for left edge. [CHAR LIMIT=30] -->
- <string name="back_gesture_tutorial_playground_title_swipe_inward_left_edge" translatable="false">Try the other side</string>
- <!-- Subtitle shown during interactive parts of Back gesture tutorial for left edge. [CHAR LIMIT=60] -->
- <string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge" translatable="false">That\'s it! Now try swiping from the left edge.</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
- <string name="back_gesture_feedback_swipe_too_far_from_left_edge" translatable="false">Make sure you swipe from the far left edge</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_left_edge">Make sure you swipe from the far-left edge.</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
- <string name="back_gesture_feedback_cancelled_left_edge" translatable="false">Make sure you swipe straight to the right and let go</string>
-
+ <string name="back_gesture_feedback_cancelled_left_edge">Make sure you swipe from the left edge to the middle of the screen and let go.</string>
+ <!-- Feedback shown after completing the left back gesture before continuing on to the right edge. [CHAR LIMIT=60] -->
+ <string name="back_gesture_feedback_complete_left_edge">That\'s it! Now try swiping from the right edge.</string>
+ <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
+ <string name="back_gesture_feedback_swipe_too_far_from_right_edge">Make sure you swipe from the far-right edge.</string>
+ <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is cancelled. [CHAR LIMIT=100] -->
+ <string name="back_gesture_feedback_cancelled_right_edge">Make sure you swipe from the right edge to the middle of the screen and let go.</string>
+ <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
+ <string name="back_gesture_feedback_complete">You completed the go back gesture. Next up, learn how to go Home.</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
- <string name="back_gesture_feedback_swipe_in_nav_bar" translatable="false">Make sure you don\'t swipe too close to the bottom of the screen</string>
+ <string name="back_gesture_feedback_swipe_in_nav_bar">Make sure you don\'t swipe too close to the bottom of the screen.</string>
<!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
- <string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
-
- <!-- Title shown during interactive part of Home gesture tutorial. [CHAR LIMIT=30] -->
- <string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
- <!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
- <string name="home_gesture_tutorial_playground_subtitle" translatable="false">Try swiping upward from the bottom edge of the screen</string>
+ <string name="back_gesture_tutorial_confirm_subtitle">To change the sensitivity of the back gesture, go to Settings</string>
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
- <string name="home_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
- <!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
- <string name="home_gesture_feedback_overview_detected" translatable="false">Make sure you don\'t pause before letting go</string>
- <!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
- <string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
+ <!-- Introduction title for the Back gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="back_gesture_intro_title">Swipe to go back</string>
+ <!-- Introduction subtitle for the Back gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="back_gesture_intro_subtitle">To go back to the last screen, swipe from the left or right edge to the middle of the screen.</string>
- <!-- Title shown during interactive part of Overview gesture tutorial. [CHAR LIMIT=30] -->
- <string name="overview_gesture_tutorial_playground_title" translatable="false">Tutorial: Switch Apps</string>
- <!-- Subtitle shown during interactive parts of Overview gesture tutorial. [CHAR LIMIT=60] -->
- <string name="overview_gesture_tutorial_playground_subtitle" translatable="false">Swipe up from the bottom of the screen and hold</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
+ <!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
+ <string name="home_gesture_feedback_overview_detected">Make sure you don\'t pause before letting go.</string>
+ <!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
+ <string name="home_gesture_feedback_wrong_swipe_direction">Make sure you swipe straight up.</string>
+ <string name="home_gesture_feedback_complete">You completed the go Home gesture. Next up, learn how to switch apps.</string>
+ <!-- Introduction title for the Home gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="home_gesture_intro_title">Swipe to go home</string>
+ <!-- Introduction subtitle for the Home gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="home_gesture_intro_subtitle">Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.</string>
+
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the Home gesture is detected. [CHAR LIMIT=100] -->
- <string name="overview_gesture_feedback_home_detected" translatable="false">Try holding the window for longer before releasing</string>
+ <string name="overview_gesture_feedback_home_detected">Try holding the window for longer before releasing.</string>
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
- <string name="overview_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up and pause</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction">Make sure you swipe straight up, then pause.</string>
+ <string name="overview_gesture_feedback_complete">You completed the switch apps gesture. You\'re ready to use your phone!</string>
+ <!-- Introduction title for the Overview gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="overview_gesture_intro_title">Swipe to switch apps</string>
+ <!-- Introduction subtitle for the Overview gesture tutorial. [CHAR LIMIT=100] -->
+ <string name="overview_gesture_intro_subtitle">Swipe up from the bottom of your screen, hold, then release.</string>
<!-- Title shown during interactive part of Assistant gesture tutorial. [CHAR LIMIT=30] -->
<string name="assistant_gesture_tutorial_playground_title" translatable="false">Tutorial: Assistant</string>
<!-- Subtitle shown during interactive parts of Assistant gesture tutorial. [CHAR LIMIT=60] -->
<string name="assistant_gesture_tutorial_playground_subtitle" translatable="false">Try swiping diagonally from a bottom corner of the screen</string>
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture is started too far from the corner. [CHAR LIMIT=100] -->
- <string name="assistant_gesture_feedback_swipe_too_far_from_corner" translatable="false">Make sure you swipe from a bottom corner of the screen</string>
+ <string name="assistant_gesture_feedback_swipe_too_far_from_corner" translatable="false">Make sure you swipe from a bottom corner of the screen.</string>
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go diagonally enough. [CHAR LIMIT=100] -->
- <string name="assistant_gesture_feedback_swipe_not_diagonal" translatable="false">Make sure you swipe diagonally</string>
+ <string name="assistant_gesture_feedback_swipe_not_diagonal" translatable="false">Make sure you swipe diagonally.</string>
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
- <string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
+ <string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further.</string>
<!-- Title shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=30] -->
<string name="sandbox_mode_title" translatable="false">Sandbox Mode</string>
@@ -172,11 +163,19 @@
<string name="sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the left/right edge of the screen</string>
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
- <string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
- <!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
- <string name="gesture_tutorial_action_button_label_done" translatable="false">Done</string>
+ <string name="gesture_tutorial_confirm_title">All set</string>
+ <!-- Button text shown on a button on the feedback popup to proceed to the next tutorial step. [CHAR LIMIT=14] -->
+ <string name="gesture_tutorial_action_button_label_next">Next</string>
+ <!-- Button text shown on a button on the feedback popup to complete the tutorial. [CHAR LIMIT=14] -->
+ <string name="gesture_tutorial_action_button_label_done">Done</string>
<!-- Button text shown on a button to go to Settings. [CHAR LIMIT=14] -->
- <string name="gesture_tutorial_action_button_label_settings" translatable="false">Settings</string>
+ <string name="gesture_tutorial_action_button_label_settings">Settings</string>
+ <!-- Feedback title to try again. [CHAR LIMIT=30] -->
+ <string name="gesture_tutorial_try_again">Try again</string>
+ <!-- Feedback title for a successful gesture. [CHAR LIMIT=30] -->
+ <string name="gesture_tutorial_nice">Nice!</string>
+ <!-- Feedback subtext displaying the current step and the total number of steps for the tutorial. [CHAR LIMIT=30] -->
+ <string name="gesture_tutorial_step">Tutorial <xliff:g id="current">%1$d</xliff:g>/<xliff:g id="total">%2$d</xliff:g></string>
<!-- ******* Overview ******* -->
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
@@ -185,4 +184,14 @@
<string name="action_screenshot">Screenshot</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
+
+ <!-- ******* Skip tutorial dialog ******* -->
+ <!-- Title for the dialog that allows the user to skip the gesture navigation tutorial. [CHAR_LIMIT=40] -->
+ <string name="skip_tutorial_dialog_title">Skip navigation tutorial?</string>
+ <!-- Subtitle for the dialog that allows the user to skip the gesture navigation tutorial. [CHAR_LIMIT=40] -->
+ <string name="skip_tutorial_dialog_subtitle">You can find this later in the Tips app</string>
+ <!-- Button text shown on a button on the tutorial skip dialog to return to the tutorial. [CHAR LIMIT=14] -->
+ <string name="gesture_tutorial_action_button_label_cancel">Cancel</string>
+ <!-- Button text shown on a button on the tutorial skip dialog to exit the tutorial. [CHAR LIMIT=14] -->
+ <string name="gesture_tutorial_action_button_label_skip">Skip</string>
</resources>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index df089f6..e56397a 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -81,7 +81,7 @@
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
<item name="android:textColor">@color/overview_button</item>
<item name="android:drawableTint">@color/overview_button</item>
- <item name="android:tint">?attr/workspaceTextColor</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
<item name="android:drawablePadding">8dp</item>
<item name="android:textAllCaps">false</item>
</style>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 6ba7414..e9ded8a 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -92,6 +92,7 @@
private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
// Will be updated when dragging from taskbar.
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
+ private SplitPlaceholderView mSplitPlaceholderView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -215,12 +216,12 @@
SysUINavigationMode.INSTANCE.get(this).updateMode();
mActionsView = findViewById(R.id.overview_actions_view);
- SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
+ mSplitPlaceholderView = findViewById(R.id.split_placeholder);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
- splitPlaceholderView.init(
+ mSplitPlaceholderView.init(
new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this))
);
- overviewPanel.init(mActionsView, splitPlaceholderView);
+ overviewPanel.init(mActionsView, mSplitPlaceholderView);
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
mAppTransitionManager = new QuickstepTransitionManager(this);
@@ -256,6 +257,10 @@
return (T) mActionsView;
}
+ public SplitPlaceholderView getSplitPlaceholderView() {
+ return mSplitPlaceholderView;
+ }
+
@Override
protected void closeOpenViews(boolean animate) {
super.closeOpenViews(animate);
@@ -336,6 +341,14 @@
}
@Override
+ public float getNormalTaskbarScale() {
+ if (mTaskbarController != null) {
+ return mTaskbarController.getTaskbarScaleOnHome();
+ }
+ return super.getNormalTaskbarScale();
+ }
+
+ @Override
public void onDragLayerHierarchyChanged() {
onLauncherStateOrFocusChanged();
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 64b22d4..82a83fc 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -68,6 +68,7 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.util.ActivityOptionsWrapper;
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 8e92b59..cc3ccea 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -237,7 +237,9 @@
setTranslationY(scroll);
}
setAlpha(mScrolledOut ? 0 : 1);
- AlphaUpdateListener.updateVisibility(this);
+ if (getVisibility() != GONE) {
+ AlphaUpdateListener.updateVisibility(this);
+ }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
index ce94305..1f268cc 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
@@ -48,10 +48,6 @@
@Override
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation animation) {
- if (config.onlyPlayAtomicComponent()) {
- return;
- }
-
if (SysUINavigationMode.getMode(mLauncher) != TWO_BUTTONS) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index fe8f0c6..249ef3a 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -193,7 +193,6 @@
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation animation) {
if (mSurface == null
- || config.onlyPlayAtomicComponent()
|| config.hasAnimationFlag(SKIP_DEPTH_CONTROLLER)
|| mIgnoreStateChangesDuringMultiWindowAnimation) {
return;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
similarity index 76%
rename from quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
rename to quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
index 8745a7c..7c54e2d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
@@ -20,20 +20,21 @@
import android.animation.Animator;
import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.Utilities;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
/**
- * Works with TaskbarController to update the TaskbarView's alpha based on LauncherState, whether
- * Launcher is in the foreground, etc.
+ * Works with TaskbarController to update the TaskbarView's visual properties based on factors such
+ * as LauncherState, whether Launcher is in the foreground, etc.
*/
-public class TaskbarVisibilityController {
+public class TaskbarAnimationController {
private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
private final BaseQuickstepLauncher mLauncher;
- private final TaskbarController.TaskbarVisibilityControllerCallbacks mTaskbarCallbacks;
+ private final TaskbarController.TaskbarAnimationControllerCallbacks mTaskbarCallbacks;
// Background alpha.
private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
@@ -45,8 +46,12 @@
private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
this::updateVisibilityAlpha);
- public TaskbarVisibilityController(BaseQuickstepLauncher launcher,
- TaskbarController.TaskbarVisibilityControllerCallbacks taskbarCallbacks) {
+ // Scale.
+ private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat(
+ this::updateScale);
+
+ public TaskbarAnimationController(BaseQuickstepLauncher launcher,
+ TaskbarController.TaskbarAnimationControllerCallbacks taskbarCallbacks) {
mLauncher = launcher;
mTaskbarCallbacks = taskbarCallbacks;
}
@@ -72,6 +77,10 @@
return mTaskbarVisibilityAlphaForLauncherState;
}
+ protected AnimatedFloat getTaskbarScaleForLauncherState() {
+ return mTaskbarScaleForLauncherState;
+ }
+
protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
.setDuration(duration);
@@ -85,6 +94,7 @@
private void onTaskbarBackgroundAlphaChanged() {
mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
updateVisibilityAlpha();
+ updateScale();
}
private void updateVisibilityAlpha() {
@@ -101,6 +111,15 @@
setNavBarButtonAlpha(1f - taskbarAlpha);
}
+ private void updateScale() {
+ // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
+ // assumption being that Taskbar should always be at scale 1f regardless of the current
+ // LauncherState if Launcher is paused.
+ float scale = mTaskbarScaleForLauncherState.value;
+ scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f);
+ mTaskbarCallbacks.updateTaskbarScale(scale);
+ }
+
private void setNavBarButtonAlpha(float navBarAlpha) {
SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 5202d91..ccf6b41 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -27,7 +27,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.systemui.shared.system.ViewTreeObserverWrapper;
@@ -83,18 +82,13 @@
private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
return insetsInfo -> {
- if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
- || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) {
- // We're invisible or dragging out of taskbar, let touches pass through us.
+ if (mControllerCallbacks.isTaskbarTouchable()) {
+ // Accept touches anywhere in our bounds.
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
+ } else {
+ // Let touches pass through us.
insetsInfo.touchableRegion.setEmpty();
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- // TODO(b/182234653): Shouldn't need to do this, but for the meantime, reporting
- // that visibleInsets is empty allows DragEvents through. Setting them as completely
- // empty reverts to default behavior, so set 1 px instead.
- insetsInfo.visibleInsets.set(0, 0, 0, 1);
- } else {
- // We're visible again, accept touches anywhere in our bounds.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
}
// TaskbarContainerView provides insets to other apps based on contentInsets. These
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index eccc41b..559ede1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -19,8 +19,6 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -44,6 +42,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -75,7 +74,7 @@
// Layout width and height of the Taskbar in the default state.
private final Point mTaskbarSize;
private final TaskbarStateHandler mTaskbarStateHandler;
- private final TaskbarVisibilityController mTaskbarVisibilityController;
+ private final TaskbarAnimationController mTaskbarAnimationController;
private final TaskbarHotseatController mHotseatController;
private final TaskbarRecentsController mRecentsController;
private final TaskbarDragController mDragController;
@@ -90,7 +89,6 @@
private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
- private boolean mIsAnimatingToApp;
public TaskbarController(BaseQuickstepLauncher launcher,
TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) {
@@ -104,8 +102,8 @@
mWindowManager = mLauncher.getWindowManager();
mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize);
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
- mTaskbarVisibilityController = new TaskbarVisibilityController(mLauncher,
- createTaskbarVisibilityControllerCallbacks());
+ mTaskbarAnimationController = new TaskbarAnimationController(mLauncher,
+ createTaskbarAnimationControllerCallbacks());
mHotseatController = new TaskbarHotseatController(mLauncher,
createTaskbarHotseatControllerCallbacks());
mRecentsController = new TaskbarRecentsController(mLauncher,
@@ -113,8 +111,8 @@
mDragController = new TaskbarDragController(mLauncher);
}
- private TaskbarVisibilityControllerCallbacks createTaskbarVisibilityControllerCallbacks() {
- return new TaskbarVisibilityControllerCallbacks() {
+ private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
+ return new TaskbarAnimationControllerCallbacks() {
@Override
public void updateTaskbarBackgroundAlpha(float alpha) {
mTaskbarViewInApp.setBackgroundAlpha(alpha);
@@ -125,6 +123,12 @@
mTaskbarContainerView.setAlpha(alpha);
mTaskbarViewOnHome.setAlpha(alpha);
}
+
+ @Override
+ public void updateTaskbarScale(float scale) {
+ mTaskbarViewInApp.setScaleX(scale);
+ mTaskbarViewInApp.setScaleY(scale);
+ }
};
}
@@ -137,6 +141,13 @@
setTaskbarWindowFullscreen(false);
}
}
+
+ @Override
+ public boolean isTaskbarTouchable() {
+ return mTaskbarContainerView.getAlpha() > AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
+ && mTaskbarViewInApp.getVisibility() == View.VISIBLE
+ && !mIsAnimatingToLauncher;
+ }
};
}
@@ -242,20 +253,25 @@
mTaskbarContainerView.init(mTaskbarViewInApp);
addToWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
- mTaskbarVisibilityController.init();
+ mTaskbarAnimationController.init();
mHotseatController.init();
mRecentsController.init();
- SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed()
- ? getTaskbarScaleOnHome() : 1f);
- updateWhichTaskbarViewIsVisible();
+ setWhichTaskbarViewIsVisible(mLauncher.hasBeenResumed()
+ ? mTaskbarViewOnHome
+ : mTaskbarViewInApp);
}
private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
return new TaskbarStateHandlerCallbacks() {
@Override
public AnimatedFloat getAlphaTarget() {
- return mTaskbarVisibilityController.getTaskbarVisibilityForLauncherState();
+ return mTaskbarAnimationController.getTaskbarVisibilityForLauncherState();
+ }
+
+ @Override
+ public AnimatedFloat getScaleTarget() {
+ return mTaskbarAnimationController.getTaskbarScaleForLauncherState();
}
};
}
@@ -274,9 +290,11 @@
mTaskbarContainerView.cleanup();
removeFromWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(null);
- mTaskbarVisibilityController.cleanup();
+ mTaskbarAnimationController.cleanup();
mHotseatController.cleanup();
mRecentsController.cleanup();
+
+ setWhichTaskbarViewIsVisible(null);
}
private void removeFromWindowManager() {
@@ -342,12 +360,10 @@
*/
public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(0, duration));
+ anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration));
if (toState != null) {
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
}
- anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(),
- getTaskbarScaleOnHome(), LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -359,7 +375,7 @@
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimatingToLauncher = false;
- updateWhichTaskbarViewIsVisible();
+ setWhichTaskbarViewIsVisible(mTaskbarViewOnHome);
}
});
@@ -368,19 +384,16 @@
private Animator createAnimToApp(long duration) {
PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration));
- anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR);
+ anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration));
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mIsAnimatingToApp = true;
mTaskbarViewInApp.updateHotseatItemsVisibility();
- updateWhichTaskbarViewIsVisible();
+ setWhichTaskbarViewIsVisible(mTaskbarViewInApp);
}
@Override
public void onAnimationEnd(Animator animation) {
- mIsAnimatingToApp = false;
}
});
return anim.buildAnim();
@@ -390,7 +403,7 @@
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
*/
public void setIsImeVisible(boolean isImeVisible) {
- mTaskbarVisibilityController.animateToVisibilityForIme(isImeVisible ? 0 : 1);
+ mTaskbarAnimationController.animateToVisibilityForIme(isImeVisible ? 0 : 1);
}
/**
@@ -483,18 +496,12 @@
mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
}
- private void updateWhichTaskbarViewIsVisible() {
- boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
- || mIsAnimatingToApp;
- if (isInApp) {
- mTaskbarViewInApp.setVisibility(View.VISIBLE);
- mTaskbarViewOnHome.setVisibility(View.INVISIBLE);
- mLauncher.getHotseat().setIconsAlpha(0);
- } else {
- mTaskbarViewInApp.setVisibility(View.INVISIBLE);
- mTaskbarViewOnHome.setVisibility(View.VISIBLE);
- mLauncher.getHotseat().setIconsAlpha(1);
- }
+ private void setWhichTaskbarViewIsVisible(@Nullable TaskbarView visibleTaskbar) {
+ mTaskbarViewInApp.setVisibility(visibleTaskbar == mTaskbarViewInApp
+ ? View.VISIBLE : View.INVISIBLE);
+ mTaskbarViewOnHome.setVisibility(visibleTaskbar == mTaskbarViewOnHome
+ ? View.VISIBLE : View.INVISIBLE);
+ mLauncher.getHotseat().setIconsAlpha(visibleTaskbar != mTaskbarViewInApp ? 1f : 0f);
}
/**
@@ -527,15 +534,17 @@
*/
protected interface TaskbarStateHandlerCallbacks {
AnimatedFloat getAlphaTarget();
+ AnimatedFloat getScaleTarget();
}
/**
- * Contains methods that TaskbarVisibilityController can call to interface with
+ * Contains methods that TaskbarAnimationController can call to interface with
* TaskbarController.
*/
- protected interface TaskbarVisibilityControllerCallbacks {
+ protected interface TaskbarAnimationControllerCallbacks {
void updateTaskbarBackgroundAlpha(float alpha);
void updateTaskbarVisibilityAlpha(float alpha);
+ void updateTaskbarScale(float scale);
}
/**
@@ -543,6 +552,7 @@
*/
protected interface TaskbarContainerViewCallbacks {
void onViewRemoved();
+ boolean isTaskbarTouchable();
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
index 0a3819d..9fc7d99 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -53,8 +53,10 @@
}
AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
+ AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget();
boolean isTaskbarVisible = (state.getVisibleElements(mLauncher) & TASKBAR) != 0;
alphaTarget.updateValue(isTaskbarVisible ? 1f : 0f);
+ scaleTarget.updateValue(state.getTaskbarScale(mLauncher));
}
@Override
@@ -65,7 +67,10 @@
}
AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
+ AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget();
boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
+ animation.setFloat(scaleTarget, AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher),
+ LINEAR);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index d65c59e..a3a1fef 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -26,8 +26,6 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
@@ -83,10 +81,6 @@
@Override
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation builder) {
- if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
- // The entire recents animation is played atomically.
- return;
- }
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
@@ -122,6 +116,11 @@
config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
setter.setFloat(scrim, SCRIM_MULTIPLIER, 1f,
config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
+ if (toState.areElementsVisible(mLauncher, LauncherState.SPLIT_PLACHOLDER_VIEW)) {
+ scrim.updateStableScrimmedView(mLauncher.getSplitPlaceholderView());
+ } else {
+ scrim.updateStableScrimmedView(mLauncher.getOverviewPanel());
+ }
setter.setFloat(
mRecentsView, getTaskModalnessProperty(),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index bae97d7..0ceb8c7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -35,6 +36,7 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.view.HapticFeedbackConstants;
import android.view.View;
import com.android.launcher3.BaseQuickstepLauncher;
@@ -234,7 +236,6 @@
@Override
public void onDestroy() {
super.onDestroy();
- getAppsView().getSearchUiManager().destroySearch();
mHotseatPredictionController.destroy();
}
@@ -251,6 +252,11 @@
}
break;
}
+ case HINT_STATE_TWO_BUTTON_ORDINAL: {
+ getStateManager().goToState(OVERVIEW);
+ getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ break;
+ }
case OVERVIEW_STATE_ORDINAL: {
RecentsView rv = getOverviewPanel();
sendCustomAccessibilityEvent(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e1456b1..9097c8b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -103,18 +103,17 @@
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
LauncherState state) {
- float clearAllButtonAlpha = (state.getVisibleElements(mLauncher) & CLEAR_ALL_BUTTON) != 0
- ? 1 : 0;
+ float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
- float overviewButtonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0
- ? 1 : 0;
+ float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS)
+ && mRecentsView.shouldShowOverviewActionsForState(state) ? 1 : 0;
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator(
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
float splitPlaceholderAlpha = state.areElementsVisible(mLauncher, SPLIT_PLACHOLDER_VIEW) ?
- 1 : 0;
+ 0.7f : 0;
propertySetter.setFloat(mRecentsView.getSplitPlaceholder(), ALPHA_FLOAT,
splitPlaceholderAlpha, LINEAR);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
index 36c0e34..1417995 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -102,9 +102,11 @@
private void notifyChange() {
// Create a new array to avoid concurrent modification when the activity destroys itself.
mTempListeners = mListeners.toArray(mTempListeners);
- for (OnChangeListener listener : mTempListeners) {
+ for (int i = mTempListeners.length - 1; i >= 0; --i) {
+ final OnChangeListener listener = mTempListeners[i];
if (listener != null) {
listener.onExtractedColorsChanged(this);
+ mTempListeners[i] = null;
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index bdba482..6f084a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
@@ -70,13 +71,12 @@
}
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
- Rect out = new Rect();
- activity.<RecentsView>getOverviewPanel().getTaskSize(out);
- int taskHeight = out.height();
- activity.<RecentsView>getOverviewPanel().getModalTaskSize(out);
- int newHeight = out.height();
+ Point taskSize = activity.<RecentsView>getOverviewPanel().getSelectedTaskSize();
+ Rect modalTaskSize = new Rect();
+ activity.<RecentsView>getOverviewPanel().getModalTaskSize(modalTaskSize);
- float scale = (float) newHeight / taskHeight;
+ float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
+ (float) modalTaskSize.width() / taskSize.x);
return new float[] {scale, NO_OFFSET};
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d8a5f9b..95a855a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -83,6 +83,11 @@
}
@Override
+ public float getTaskbarScale(Launcher launcher) {
+ return 1f;
+ }
+
+ @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -94,13 +99,12 @@
@Override
public int getVisibleElements(Launcher launcher) {
- return displayOverviewTasksAsGrid(launcher.getDeviceProfile()) ? CLEAR_ALL_BUTTON
- : CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
+ return CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
}
@Override
public float getOverviewScrimAlpha(Launcher launcher) {
- return 0.5f;
+ return 1f;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index de7be5d..ba61923 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -18,6 +18,7 @@
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherState.HINT_STATE;
+import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
@@ -115,7 +116,8 @@
qsbContainer.setScaleY(0.92f);
}
}
- } else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
+ } else if ((fromState == NORMAL || fromState == HINT_STATE
+ || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) {
if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 6c71995..464b90a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -38,7 +38,6 @@
import android.animation.ValueAnimator;
import android.graphics.PointF;
import android.view.MotionEvent;
-import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
@@ -108,11 +107,11 @@
}
@Override
- protected float initCurrentAnimation(int animComponents) {
- float progressMultiplier = super.initCurrentAnimation(animComponents);
+ protected float initCurrentAnimation() {
+ float progressMultiplier = super.initCurrentAnimation();
if (mToState == HINT_STATE) {
// Track the drag across the entire height of the screen.
- progressMultiplier = -1 / getShiftRange();
+ progressMultiplier = -1f / mLauncher.getDeviceProfile().heightPx;
}
return progressMultiplier;
}
@@ -155,11 +154,6 @@
super.onDragEnd(velocity);
}
- View searchView = mLauncher.getHotseat().getQsb();
- if (searchView instanceof FeedbackHandler) {
- ((FeedbackHandler) searchView).resetFeedback();
- }
-
mMotionPauseDetector.clear();
mNormalToHintOverviewScrimAnimator = null;
if (mLauncher.isInState(OVERVIEW)) {
@@ -188,13 +182,13 @@
}
mNormalToHintOverviewScrimAnimator = null;
mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
- mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
- mOverviewResistYAnim = AnimatorControllerWithResistance
- .createRecentsResistanceFromOverviewAnim(mLauncher, null)
- .createPlaybackController();
- mReachedOverview = true;
- maybeSwipeInteractionToOverviewComplete();
- })));
+ mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
+ mOverviewResistYAnim = AnimatorControllerWithResistance
+ .createRecentsResistanceFromOverviewAnim(mLauncher, null)
+ .createPlaybackController();
+ mReachedOverview = true;
+ maybeSwipeInteractionToOverviewComplete();
+ })));
mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
mCurrentAnimation.dispatchOnCancel();
@@ -203,7 +197,7 @@
}
private void maybeSwipeInteractionToOverviewComplete() {
- if (mReachedOverview && mDetector.isSettlingState()) {
+ if (mReachedOverview && !mDetector.isDraggingState()) {
onSwipeInteractionCompleted(OVERVIEW);
}
}
@@ -245,7 +239,7 @@
private void goToOverviewOrHomeOnDragEnd(float velocity) {
boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
if (goToHomeInsteadOfOverview) {
- new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL))
+ new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL))
.animateWithVelocity(velocity);
}
if (mReachedOverview) {
@@ -281,17 +275,14 @@
LauncherState fromState, LauncherState toState) {
if (fromState == NORMAL && toState == ALL_APPS) {
StateAnimationConfig builder = new StateAnimationConfig();
- // Fade in prediction icons quickly, then rest of all apps after reaching overview.
- float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
- - OVERVIEW.getVerticalProgress(mLauncher);
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
ACCEL,
0,
- ALL_APPS_CONTENT_FADE_THRESHOLD));
+ ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
ACCEL,
- progressToReachOverview,
- progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
+ ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD,
+ ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
// Get workspace out of the way quickly, to prepare for potential pause.
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
@@ -300,29 +291,17 @@
return builder;
} else if (fromState == ALL_APPS && toState == NORMAL) {
StateAnimationConfig builder = new StateAnimationConfig();
- // Keep all apps/predictions opaque until the very end of the transition.
- float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
+
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
DEACCEL,
- progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
- progressToReachOverview));
+ 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
+ 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
DEACCEL,
- 1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
+ 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
1));
return builder;
}
return super.getConfigForStates(fromState, toState);
}
-
- /**
- * Interface for views with feedback animation requiring reset
- */
- public interface FeedbackHandler {
-
- /**
- * reset searchWidget feedback
- */
- void resetFeedback();
- }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 4766870..61cd13b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -33,6 +33,7 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
@@ -372,7 +373,7 @@
// animation as from an app.
StateAnimationConfig config = new StateAnimationConfig();
// Update mNonOverviewAnim to do nothing so it doesn't interfere.
- config.animFlags = 0;
+ config.animFlags = SKIP_ALL_ANIMATIONS;
updateNonOverviewAnim(targetState, config);
nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index facfb9d..b8f9452 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -23,17 +23,9 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.util.Log;
import android.view.MotionEvent;
-import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -41,8 +33,6 @@
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.uioverrides.states.OverviewState;
@@ -59,9 +49,15 @@
private static final String TAG = "PortraitStatesTouchCtrl";
/**
- * The progress at which all apps content will be fully visible when swiping up from overview.
+ * The progress at which all apps content will be fully visible.
*/
- protected static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
+ protected static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
+
+ /**
+ * Minimum clamping progress for fading in all apps content
+ */
+ protected static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.4f;
+
/**
* The progress at which recents will begin fading out when swiping up from overview.
@@ -70,11 +66,6 @@
private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
- private final InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
-
- // If true, we will finish the current animation instantly on second touch.
- private boolean mFinishFastOnSecondTouch;
-
public PortraitStatesTouchController(Launcher l) {
super(l, SingleAxisSwipeDetector.VERTICAL);
mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
@@ -85,10 +76,6 @@
// If we are swiping to all apps instead of overview, allow it from anywhere.
boolean interceptAnywhere = mLauncher.isInState(NORMAL);
if (mCurrentAnimation != null) {
- if (mFinishFastOnSecondTouch) {
- mCurrentAnimation.getAnimationPlayer().end();
- }
-
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()
|| interceptAnywhere) {
@@ -96,11 +83,7 @@
// the touch is below the current all apps progress (to allow for double swipe).
return true;
}
- // Otherwise, make sure everything is settled and don't intercept so they can scroll
- // recents, dismiss a task, etc.
- if (mAtomicAnim != null) {
- mAtomicAnim.end();
- }
+ // Otherwise, don't intercept so they can scroll recents, dismiss a task, etc.
return false;
}
if (mLauncher.isInState(ALL_APPS)) {
@@ -136,43 +119,17 @@
return fromState;
}
- private StateAnimationConfig getNormalToOverviewAnimation() {
- mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
-
- StateAnimationConfig builder = new StateAnimationConfig();
- builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper);
- return builder;
- }
-
- private static StateAnimationConfig getOverviewToAllAppsAnimation() {
- StateAnimationConfig builder = new StateAnimationConfig();
- builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
- 0, ALL_APPS_CONTENT_FADE_THRESHOLD));
- builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(DEACCEL,
- RECENTS_FADE_THRESHOLD, 1));
- return builder;
- }
-
- private StateAnimationConfig getAllAppsToOverviewAnimation() {
- StateAnimationConfig builder = new StateAnimationConfig();
- builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
- 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
- builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(ACCEL,
- 0f, 1 - RECENTS_FADE_THRESHOLD));
- return builder;
- }
-
private StateAnimationConfig getNormalToAllAppsAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
- 0, ALL_APPS_CONTENT_FADE_THRESHOLD));
+ 0, ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
return builder;
}
private StateAnimationConfig getAllAppsToNormalAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
- 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
+ 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, 1));
return builder;
}
@@ -180,24 +137,18 @@
protected StateAnimationConfig getConfigForStates(
LauncherState fromState, LauncherState toState) {
final StateAnimationConfig config;
- if (fromState == NORMAL && toState == OVERVIEW) {
- config = getNormalToOverviewAnimation();
- } else if (fromState == OVERVIEW && toState == ALL_APPS) {
- config = getOverviewToAllAppsAnimation();
- } else if (fromState == ALL_APPS && toState == OVERVIEW) {
- config = getAllAppsToOverviewAnimation();
- } else if (fromState == NORMAL && toState == ALL_APPS) {
+ if (fromState == NORMAL && toState == ALL_APPS) {
config = getNormalToAllAppsAnimation();
} else if (fromState == ALL_APPS && toState == NORMAL) {
config = getAllAppsToNormalAnimation();
- } else {
+ } else {
config = new StateAnimationConfig();
}
return config;
}
@Override
- protected float initCurrentAnimation(@AnimationFlags int animFlags) {
+ protected float initCurrentAnimation() {
float range = getShiftRange();
long maxAccuracy = (long) (2 * range);
@@ -208,7 +159,6 @@
final StateAnimationConfig config = totalShift == 0 ? new StateAnimationConfig()
: getConfigForStates(mFromState, mToState);
- config.animFlags = animFlags;
config.duration = maxAccuracy;
if (mCurrentAnimation != null) {
@@ -243,35 +193,6 @@
}
@Override
- protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
- LauncherState targetState, float velocity, boolean isFling) {
- super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
- velocity, isFling);
- handleFirstSwipeToOverview(animator, expectedDuration, targetState, velocity, isFling);
- }
-
- private void handleFirstSwipeToOverview(final ValueAnimator animator,
- final long expectedDuration, final LauncherState targetState, final float velocity,
- final boolean isFling) {
- if (UNSTABLE_SPRINGS.get() && mFromState == OVERVIEW && mToState == ALL_APPS
- && targetState == OVERVIEW) {
- mFinishFastOnSecondTouch = true;
- } else if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
- mFinishFastOnSecondTouch = true;
- if (isFling && expectedDuration != 0) {
- // Update all apps interpolator to add a bit of overshoot starting from currFraction
- final float currFraction = mCurrentAnimation.getProgressFraction();
- mAllAppsInterpolatorWrapper.baseInterpolator = Interpolators.clampToProgress(
- Interpolators.overshootInterpolatorForVelocity(velocity), currFraction, 1);
- animator.setDuration(Math.min(expectedDuration, ATOMIC_DURATION))
- .setInterpolator(LINEAR);
- }
- } else {
- mFinishFastOnSecondTouch = false;
- }
- }
-
- @Override
protected void onSwipeInteractionCompleted(LauncherState targetState) {
super.onSwipeInteractionCompleted(targetState);
if (mStartState == NORMAL && targetState == OVERVIEW) {
@@ -283,7 +204,7 @@
* Whether the motion event is over the hotseat.
*
* @param launcher the launcher activity
- * @param ev the event to check
+ * @param ev the event to check
* @return true if the event is over the hotseat
*/
static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) {
@@ -296,16 +217,6 @@
return launcher.getDragLayer().getHeight() - hotseatHeight;
}
- private static class InterpolatorWrapper implements Interpolator {
-
- public TimeInterpolator baseInterpolator = LINEAR;
-
- @Override
- public float getInterpolation(float v) {
- return baseInterpolator.getInterpolation(v);
- }
- }
-
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index fc9e1bb..94a7442 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -101,7 +101,7 @@
}
@Override
- protected float initCurrentAnimation(int animComponents) {
+ protected float initCurrentAnimation() {
StateAnimationConfig config = new StateAnimationConfig();
setupInterpolators(config);
config.duration = (long) (getShiftRange() * 2);
@@ -137,14 +137,17 @@
private void updateFullscreenProgress(float progress) {
mOverviewPanel.setFullscreenProgress(progress);
- int sysuiFlags = 0;
if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+ int sysuiFlags = 0;
TaskView tv = mOverviewPanel.getTaskViewAt(0);
if (tv != null) {
sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
}
+ mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+ } else {
+ mLauncher.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, mOverviewPanel.hasLightBackground());
}
- mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
index 0ed5291..8f9c014 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
@@ -32,8 +32,8 @@
}
@Override
- protected float initCurrentAnimation(int animComponents) {
- float multiplier = super.initCurrentAnimation(animComponents);
+ protected float initCurrentAnimation() {
+ float multiplier = super.initCurrentAnimation();
return mLauncher.getDeviceProfile().isSeascape() ? multiplier : -multiplier;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
index faf5054..3f7190f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
@@ -17,17 +17,18 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
import static com.android.launcher3.AbstractFloatingView.getOpenView;
+import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import android.animation.ValueAnimator;
+import android.os.SystemClock;
import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.quickstep.SystemUiProxy;
@@ -91,10 +92,10 @@
if (mIsTransposed) {
boolean draggingFromNav =
mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
- return draggingFromNav ? OVERVIEW : NORMAL;
+ return draggingFromNav ? HINT_STATE_TWO_BUTTON : NORMAL;
} else {
LauncherState startState = mStartState != null ? mStartState : fromState;
- return isDragTowardPositive ^ (startState == OVERVIEW) ? OVERVIEW : NORMAL;
+ return isDragTowardPositive ^ (startState == OVERVIEW) ? HINT_STATE_TWO_BUTTON : NORMAL;
}
}
@@ -104,6 +105,12 @@
super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
velocity, isFling);
mFinishFastOnSecondTouch = !mIsTransposed && mFromState == NORMAL;
+
+ if (targetState == HINT_STATE_TWO_BUTTON) {
+ // We were going to HINT_STATE_TWO_BUTTON, but end that animation immediately so we go
+ // to OVERVIEW instead.
+ animator.setDuration(0);
+ }
}
@Override
@@ -113,21 +120,35 @@
}
@Override
- protected float initCurrentAnimation(@AnimationFlags int animComponent) {
+ protected float initCurrentAnimation() {
float range = getShiftRange();
long maxAccuracy = (long) (2 * range);
mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
- maxAccuracy, animComponent);
+ maxAccuracy);
return (mLauncher.getDeviceProfile().isSeascape() ? 1 : -1) / range;
}
@Override
+ protected void updateProgress(float fraction) {
+ super.updateProgress(fraction);
+
+ // We have reached HINT_STATE, end the gesture now to go to OVERVIEW.
+ if (fraction >= 1 && mToState == HINT_STATE_TWO_BUTTON) {
+ final long now = SystemClock.uptimeMillis();
+ MotionEvent event = MotionEvent.obtain(now, now,
+ MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ mDetector.onTouchEvent(event);
+ event.recycle();
+ }
+ }
+
+ @Override
protected void onSwipeInteractionCompleted(LauncherState targetState) {
super.onSwipeInteractionCompleted(targetState);
if (!mIsTransposed) {
mContinuousTouchCount++;
}
- if (mStartState == NORMAL && targetState == OVERVIEW) {
+ if (mStartState == NORMAL && targetState == HINT_STATE_TWO_BUTTON) {
SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
} else if (targetState == NORMAL
&& mContinuousTouchCount >= MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index f4ef1f7..2a903eb 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
-import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -46,6 +45,8 @@
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
+import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -92,16 +93,16 @@
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
-import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
+import com.android.quickstep.util.InputProxyHandlerFactory;
import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.SwipePipToHomeAnimator;
import com.android.quickstep.util.TransformParams;
@@ -113,12 +114,10 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskInfoCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -200,7 +199,7 @@
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public static final long MAX_SWIPE_DURATION = 350;
- public static final long MIN_OVERSHOOT_DURATION = 120;
+ public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
private static final float SWIPE_DURATION_MULTIPLIER =
@@ -218,6 +217,8 @@
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim mRunningWindowAnim;
+ // Possible second animation running at the same time as mRunningWindowAnim
+ private Animator mParallelRunningAnim;
private boolean mIsMotionPaused;
private boolean mHasMotionEverBeenPaused;
@@ -255,7 +256,10 @@
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
- new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler);
+ new InputConsumerProxy(inputConsumer, () -> {
+ endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
+ endLauncherTransitionController();
+ }, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -315,9 +319,9 @@
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
- this::notifyTransitionCancelled);
+ this::resetStateForAnimationCancel);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_FINISH_WITH_NO_END,
- this::notifyTransitionCancelled);
+ this::resetStateForAnimationCancel);
if (!LIVE_TILE.get()) {
mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
@@ -653,8 +657,13 @@
|| (quickswitchThresholdPassed && centermostTaskFlags != 0));
mRecentsAnimationController.setSplitScreenMinimized(swipeUpThresholdPassed);
- int sysuiFlags = swipeUpThresholdPassed ? 0 : centermostTaskFlags;
- mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+ if (swipeUpThresholdPassed) {
+ mActivity.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, mRecentsView.hasLightBackground());
+ } else {
+ mActivity.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, centermostTaskFlags);
+ }
}
}
@@ -783,19 +792,6 @@
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
}
- /**
- * Called to create a input proxy for the running task
- */
- @UiThread
- protected InputConsumer createNewInputProxyHandler() {
- endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
- endLauncherTransitionController();
-
- StatefulActivity activity = mActivityInterface.getCreatedActivity();
- return activity == null ? InputConsumer.NO_OP
- : new OverviewInputConsumer(mGestureState, activity, null, true);
- }
-
private void endRunningWindowAnim(boolean cancel) {
if (mRunningWindowAnim != null) {
if (cancel) {
@@ -804,6 +800,13 @@
mRunningWindowAnim.end();
}
}
+ if (mParallelRunningAnim != null) {
+ if (cancel) {
+ mParallelRunningAnim.cancel();
+ } else {
+ mParallelRunningAnim.end();
+ }
+ }
}
private void onSettledOnEndTarget() {
@@ -960,7 +963,7 @@
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
- duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
+ duration = HOME_DURATION;
} else if (endTarget == RECENTS) {
if (mRecentsView != null) {
int nearestPage = mRecentsView.getDestinationPage();
@@ -1066,7 +1069,11 @@
ActivityManagerWrapper.getInstance().registerTaskStackListener(
mActivityRestartListener);
- mActivityInterface.onAnimateToLauncher(mGestureState.getEndTarget(), duration);
+ mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
+ mGestureState.getEndTarget(), duration);
+ if (mParallelRunningAnim != null) {
+ mParallelRunningAnim.start();
+ }
}
if (mGestureState.getEndTarget() == HOME) {
@@ -1077,15 +1084,15 @@
HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome()
&& runningTaskTarget != null
- && runningTaskTarget.pictureInPictureParams != null
+ && runningTaskTarget.taskInfo.pictureInPictureParams != null
&& TaskInfoCompat.isAutoEnterPipEnabled(
- runningTaskTarget.pictureInPictureParams);
+ runningTaskTarget.taskInfo.pictureInPictureParams);
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
homeAnimFactory, runningTaskTarget, start);
mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION);
mSwipePipToHomeAnimator.setInterpolator(interpolator);
- mSwipePipToHomeAnimator.setFloatValues(0f, 1f);
+ mSwipePipToHomeAnimator.setFloatValues(FRACTION_START, FRACTION_END);
mSwipePipToHomeAnimator.start();
mRunningWindowAnim = RunningWindowAnim.wrap(mSwipePipToHomeAnimator);
} else {
@@ -1167,7 +1174,7 @@
final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext)
.startSwipePipToHome(taskInfo.topActivity,
TaskInfoCompat.getTopActivityInfo(taskInfo),
- runningTaskTarget.pictureInPictureParams,
+ runningTaskTarget.taskInfo.pictureInPictureParams,
homeRotation,
mDp.hotseatBarSizePx);
final Rect startBounds = new Rect();
@@ -1176,7 +1183,8 @@
runningTaskTarget.taskId,
taskInfo.topActivity,
runningTaskTarget.leash.getSurfaceControl(),
- TaskInfoCompat.getPipSourceRectHint(runningTaskTarget.pictureInPictureParams),
+ TaskInfoCompat.getPipSourceRectHint(
+ runningTaskTarget.taskInfo.pictureInPictureParams),
TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
startBounds,
destinationBounds,
@@ -1338,6 +1346,7 @@
mInputConsumerProxy.destroy();
mTaskAnimationManager.setLiveTileCleanUpHandler(null);
}
+ mInputConsumerProxy.unregisterCallback();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
@@ -1374,10 +1383,6 @@
mActivity.getRootView().setOnApplyWindowInsetsListener(null);
}
- private void notifyTransitionCancelled() {
- mAnimationFactory.onTransitionCancelled();
- }
-
private void resetStateForAnimationCancel() {
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
mActivityInterface.onTransitionCancelled(wasVisible);
@@ -1494,44 +1499,20 @@
mRecentsAnimationController.setFinishTaskBounds(
mSwipePipToHomeAnimator.getTaskId(),
mSwipePipToHomeAnimator.getDestinationBounds(),
- mSwipePipToHomeAnimator.getFinishWindowCrop(),
- mSwipePipToHomeAnimator.getFinishTransform());
+ mSwipePipToHomeAnimator.getFinishTransaction());
mIsSwipingPipToHome = false;
}
}
protected abstract void finishRecentsControllerToHome(Runnable callback);
- private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (mRecentsView.getRunningTaskIndex() != -1
- && mRecentsView.getRunningTaskId() == task.taskId
- && mRecentsAnimationTargets.hasTask(task.taskId)) {
- launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps);
- }
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
- mLiveTileRestartListener);
- }
- };
-
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
mRecentsView.onSwipeUpAnimationSuccess();
if (LIVE_TILE.get()) {
- mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
- appearedTaskTarget -> {
- RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
- mRecentsAnimationTargets.apps,
- mRecentsAnimationTargets.apps.length + 1);
- apps[apps.length - 1] = appearedTaskTarget;
- launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
- });
mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- mLiveTileRestartListener);
+ mTaskAnimationManager.enableLiveTileRestartListener();
}
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
@@ -1539,65 +1520,6 @@
reset();
}
- private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
- AnimatorSet anim = new AnimatorSet();
- TaskView taskView = mRecentsView.getTaskView(taskId);
- if (taskView == null || !mRecentsView.isTaskViewVisible(taskView)) {
- // TODO: Refine this animation.
- SurfaceTransactionApplier surfaceApplier =
- new SurfaceTransactionApplier(mActivity.getDragLayer());
- ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
- appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
- appAnimator.setInterpolator(ACCEL_DEACCEL);
- appAnimator.addUpdateListener(new MultiValueUpdateListener() {
- @Override
- public void onUpdate(float percent) {
- SurfaceParams.Builder builder = new SurfaceParams.Builder(
- apps[apps.length - 1].leash);
- Matrix matrix = new Matrix();
- matrix.postScale(percent, percent);
- matrix.postTranslate(mDp.widthPx * (1 - percent) / 2,
- mDp.heightPx * (1 - percent) / 2);
- builder.withAlpha(percent).withMatrix(matrix);
- surfaceApplier.scheduleApply(builder.build());
- }
- });
- anim.play(appAnimator);
- } else {
- TaskViewUtils.composeRecentsLaunchAnimator(
- anim, taskView, apps,
- mRecentsAnimationTargets.wallpapers, true /* launcherClosing */,
- mActivity.getStateManager(), mRecentsView,
- mActivityInterface.getDepthController());
- }
- anim.addListener(new AnimatorListenerAdapter(){
-
- @Override
- public void onAnimationEnd(Animator animator) {
- cleanUp(false);
- }
-
- @Override
- public void onAnimationCancel(Animator animator) {
- cleanUp(true);
- }
-
- private void cleanUp(boolean canceled) {
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.finish(false /* toRecents */,
- null /* onFinishComplete */);
- if (canceled) {
- mRecentsAnimationController = null;
- } else {
- mActivityInterface.onLaunchTaskSuccess();
- }
- ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
- }
- }
- });
- anim.start();
- }
-
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == ACTIVITY_TYPE_HOME;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 0415009..147297a 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -206,18 +206,17 @@
Rect gridRect = new Rect();
calculateGridSize(context, dp, gridRect);
- int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
- float rowHeight = (gridRect.height() - rowSpacing) / 2f;
+ int verticalMargin = res.getDimensionPixelSize(
+ R.dimen.overview_grid_focus_vertical_margin);
+ float taskHeight = gridRect.height() - verticalMargin * 2;
PointF taskDimension = getTaskDimension(context, dp);
- float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
- taskDimension.x, taskDimension.y);
+ float scale = taskHeight / Math.max(taskDimension.x, taskDimension.y);
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
- int gravity = Gravity.TOP;
+ int gravity = Gravity.CENTER_VERTICAL;
gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
- gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
} else {
int taskMargin = dp.overviewTaskMarginPx;
@@ -294,6 +293,30 @@
}
/**
+ * Calculates the overview grid non-focused task size for the provided device configuration.
+ */
+ public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
+ PagedOrientationHandler orientedState) {
+ Resources res = context.getResources();
+ Rect gridRect = new Rect();
+ calculateGridSize(context, dp, gridRect);
+
+ int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
+ float rowHeight = (gridRect.height() - rowSpacing) / 2f;
+
+ PointF taskDimension = getTaskDimension(context, dp);
+ float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
+ taskDimension.x, taskDimension.y);
+ int outWidth = Math.round(scale * taskDimension.x);
+ int outHeight = Math.round(scale * taskDimension.y);
+
+ int gravity = Gravity.TOP;
+ gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+ gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
+ Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
+ }
+
+ /**
* Calculates the modal taskView size for the provided device configuration
*/
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
@@ -324,7 +347,9 @@
* Called when the gesture ends and the animation starts towards the given target. No-op by
* default, but subclasses can override to add an additional animation with the same duration.
*/
- public void onAnimateToLauncher(GestureState.GestureEndTarget endTarget, long duration) {
+ public @Nullable Animator getParallelAnimationToLauncher(
+ GestureState.GestureEndTarget endTarget, long duration) {
+ return null;
}
/**
@@ -343,8 +368,6 @@
void createActivityInterface(long transitionLength);
- default void onTransitionCancelled() { }
-
/**
* @param attached Whether to show RecentsView alongside the app window. If false, recents
* will be hidden by some property we can animate, e.g. alpha.
@@ -411,11 +434,6 @@
}
@Override
- public void onTransitionCancelled() {
- mActivity.getStateManager().goToState(mStartState, false /* animate */);
- }
-
- @Override
public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
if (mIsAttachedToWindow == attached && animate) {
return;
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 98b96b2..878f5c9 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import android.animation.Animator;
import android.content.Context;
import android.graphics.Rect;
import android.view.MotionEvent;
@@ -267,13 +268,14 @@
}
@Override
- public void onAnimateToLauncher(GestureEndTarget endTarget, long duration) {
+ public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
+ long duration) {
TaskbarController taskbarController = getTaskbarController();
if (taskbarController == null) {
- return;
+ return null;
}
LauncherState toState = stateFromGestureEndTarget(endTarget);
- taskbarController.createAnimToLauncher(toState, duration).start();
+ return taskbarController.createAnimToLauncher(toState, duration);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 1ce4201..311ac83 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -29,6 +29,7 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -134,7 +135,7 @@
// to home.
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
return mActivity.getStateManager().createAnimationToNewWorkspace(
- NORMAL, accuracy, 0 /* animComponents */);
+ NORMAL, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index d3ed791..1340abb 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -56,7 +56,6 @@
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsStateController;
import com.android.quickstep.fallback.FallbackRecentsView;
@@ -267,7 +266,7 @@
setupViews();
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
- Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+ mFallbackRecentsView.hasLightBackground());
ACTIVITY_TRACKER.handleCreate(this);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index ec585cc..82e8a93 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.graphics.Rect;
+import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
@@ -149,14 +150,13 @@
* accordingly. This should be called before `finish`
* @param taskId for which the leash should be updated
* @param destinationBounds bounds of the final PiP window
- * @param windowCrop bounds to crop as part of final transform.
- * @param float9 An array of 9 floats to be used as matrix transform.
+ * @param finishTransaction leash operations for the final transform.
*/
- public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop,
- float[] float9) {
+ public void setFinishTaskBounds(int taskId, Rect destinationBounds,
+ PictureInPictureSurfaceTransaction finishTransaction) {
UI_HELPER_EXECUTOR.execute(
- () -> mController.setFinishTaskBounds(taskId, destinationBounds, windowCrop,
- float9));
+ () -> mController.setFinishTaskBounds(taskId, destinationBounds,
+ finishTransaction));
}
/**
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 458f45a..23e35f6 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -187,7 +187,7 @@
SettingsCache.OnChangeListener onChangeListener =
enabled -> mIsOneHandedModeEnabled = enabled;
settingsCache.register(oneHandedUri, onChangeListener);
- settingsCache.dispatchOnChange(oneHandedUri);
+ mIsOneHandedModeEnabled = settingsCache.getValue(oneHandedUri);
runOnDestroy(() -> settingsCache.unregister(oneHandedUri, onChangeListener));
} else {
mIsOneHandedModeEnabled = false;
@@ -199,7 +199,7 @@
SettingsCache.OnChangeListener onChangeListener =
enabled -> mIsSwipeToNotificationEnabled = enabled;
settingsCache.register(swipeBottomNotificationUri, onChangeListener);
- settingsCache.dispatchOnChange(swipeBottomNotificationUri);
+ mIsSwipeToNotificationEnabled = settingsCache.getValue(swipeBottomNotificationUri);
runOnDestroy(() -> settingsCache.unregister(swipeBottomNotificationUri, onChangeListener));
Uri setupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index da0a664..718c5ba 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -41,13 +41,4 @@
public boolean hasTargets() {
return unfilteredApps.length != 0;
}
-
- public boolean hasTask(int taskId) {
- for (RemoteAnimationTargetCompat target : unfilteredApps) {
- if (target.taskId == taskId) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index f4b8b62..a8c09dc 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -29,7 +29,6 @@
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -67,8 +66,6 @@
// How much further we can drag past recents, as a factor of mTransitionDragLength.
protected float mDragLengthFactor = 1;
- protected final float mMaxShadowRadius;
-
protected AnimatorControllerWithResistance mWindowTransitionController;
public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
@@ -82,9 +79,6 @@
mTaskViewSimulator.getOrientationState().update(
mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
mDeviceState.getRotationTouchHelper().getDisplayRotation());
-
- mMaxShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.max_shadow_radius);
- mTransformParams.setShadowRadius(mMaxShadowRadius);
}
protected void initTransitionEndpoints(DeviceProfile dp) {
@@ -271,11 +265,9 @@
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
- float shadowRadius = Utilities.mapRange(progress, mMaxShadowRadius, 0);
mTransformParams
.setTargetAlpha(getWindowAlpha(progress))
- .setCornerRadius(cornerRadius)
- .setShadowRadius(shadowRadius);
+ .setCornerRadius(cornerRadius);
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
@@ -286,8 +278,7 @@
Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
builder.withMatrix(mMatrix)
.withWindowCrop(mCropRect)
- .withCornerRadius(params.getCornerRadius())
- .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
+ .withCornerRadius(params.getCornerRadius());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index cf71eae..1f332c4 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -88,6 +88,17 @@
}
@Override
+ public void onBackPressed() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.onBackPressed();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onBackPressed", e);
+ }
+ }
+ }
+
+ @Override
public IBinder asBinder() {
// Do nothing
return null;
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 9a454f2..b6dad2d 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,10 +17,11 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -31,13 +32,13 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.RemoteTransitionCompat;
-
-import java.util.function.Consumer;
+import com.android.systemui.shared.system.TaskStackChangeListener;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS =
@@ -49,10 +50,24 @@
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
- private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
private Runnable mLiveTileCleanUpHandler;
private Context mCtx;
+ private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
+ && activityInterface.getCreatedActivity() != null) {
+ RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
+ recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId);
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
+ mLiveTileRestartListener);
+ }
+ }
+ };
+
TaskAnimationManager(Context ctx) {
mCtx = ctx;
}
@@ -114,9 +129,14 @@
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
- if (mLaunchOtherTaskHandler != null
- && mLastGestureState.getEndTarget() == RECENTS) {
- mLaunchOtherTaskHandler.accept(appearedTaskTarget);
+ BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
+ && activityInterface.getCreatedActivity() != null) {
+ RecentsView recentsView =
+ activityInterface.getCreatedActivity().getOverviewPanel();
+ RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
+ apps[0] = appearedTaskTarget;
+ recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
return;
}
if (mController != null) {
@@ -161,17 +181,12 @@
return mCallbacks;
}
- /**
- * The passed-in handler is used to render side task launch animation in recents in live tile
- * mode.
- */
- public void setLaunchOtherTaskInLiveTileModeHandler(
- Consumer<RemoteAnimationTargetCompat> handler) {
- mLaunchOtherTaskHandler = handler;
+ public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
+ mLiveTileCleanUpHandler = cleanUpHandler;
}
- public void setLiveTileCleanUpHandler(Runnable runnable) {
- mLiveTileCleanUpHandler = runnable;
+ public void enableLiveTileRestartListener() {
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mLiveTileRestartListener);
}
/**
@@ -215,6 +230,7 @@
mLiveTileCleanUpHandler.run();
mLiveTileCleanUpHandler = null;
}
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mLiveTileRestartListener);
// Release all the target leashes
if (mTargets != null) {
@@ -231,7 +247,6 @@
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTarget = null;
- mLaunchOtherTaskHandler = null;
}
public void dump() {
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index dd0ed8f..ba1c413 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
import android.app.ActivityManager.TaskDescription;
@@ -34,7 +33,6 @@
import androidx.annotation.WorkerThread;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
@@ -137,21 +135,22 @@
// TODO: Load icon resource (b/143363444)
Bitmap icon = TaskDescriptionCompat.getIcon(desc, key.userId);
if (icon != null) {
- entry.icon = new FastBitmapDrawable(getBitmapInfo(
+ /* isInstantApp */
+ entry.icon = getBitmapInfo(
new BitmapDrawable(mContext.getResources(), icon),
key.userId,
desc.getPrimaryColor(),
- false /* isInstantApp */));
+ false /* isInstantApp */).newIcon(mContext);
} else {
activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(
key.getComponent(), key.userId);
if (activityInfo != null) {
BitmapInfo bitmapInfo = getBitmapInfo(
- mIconProvider.getIcon(activityInfo, UserHandle.of(key.userId)),
+ mIconProvider.getIcon(activityInfo),
key.userId,
desc.getPrimaryColor(),
activityInfo.applicationInfo.isInstantApp());
- entry.icon = newIcon(mContext, bitmapInfo);
+ entry.icon = bitmapInfo.newIcon(mContext);
} else {
entry.icon = getDefaultIcon(key.userId);
}
@@ -199,7 +198,7 @@
}
mDefaultIcons.put(userId, info);
}
- return new FastBitmapDrawable(info);
+ return info.newIcon(mContext);
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1fb9465..e9d2eb4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -239,8 +239,9 @@
@BinderThread
public void onSystemUiStateChanged(int stateFlags) {
MAIN_EXECUTOR.execute(() -> {
+ int lastFlags = mDeviceState.getSystemUiStateFlags();
mDeviceState.setSystemUiFlags(stateFlags);
- TouchInteractionService.this.onSystemUiFlagsChanged();
+ TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags);
});
}
@@ -362,7 +363,7 @@
mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
mInputConsumer.registerInputConsumer();
- onSystemUiFlagsChanged();
+ onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
onAssistantVisibilityChanged();
// Temporarily disable model preload
@@ -414,7 +415,7 @@
}
@UiThread
- private void onSystemUiFlagsChanged() {
+ private void onSystemUiFlagsChanged(int lastSysUIFlags) {
if (mDeviceState.isUserUnlocked()) {
int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
@@ -422,14 +423,17 @@
mOverviewComponentObserver.getActivityInterface().onSystemUiFlagsChanged(
systemUiStateFlags);
- // Update the tracing state
- if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
- Log.d(TAG, "Starting tracing.");
- ProtoTracer.INSTANCE.get(this).start();
- } else {
- Log.d(TAG, "Stopping tracing. Dumping to file="
- + ProtoTracer.INSTANCE.get(this).getTraceFile());
- ProtoTracer.INSTANCE.get(this).stop();
+ if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) !=
+ (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) {
+ // Update the tracing state
+ if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
+ Log.d(TAG, "Starting tracing.");
+ ProtoTracer.INSTANCE.get(this).start();
+ } else {
+ Log.d(TAG, "Stopping tracing. Dumping to file="
+ + ProtoTracer.INSTANCE.get(this).getTraceFile());
+ ProtoTracer.INSTANCE.get(this).stop();
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 82bfa9b..8962ec9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -20,8 +20,6 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -63,10 +61,6 @@
@Override
public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config,
PendingAnimation setter) {
- if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
- // The entire recents animation is played atomically.
- return;
- }
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
@@ -82,7 +76,9 @@
float clearAllButtonAlpha = state.hasClearAllButton() ? 1 : 0;
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
- float overviewButtonAlpha = state.hasOverviewActions(mActivity) ? 1 : 0;
+ float overviewButtonAlpha =
+ state.hasOverviewActions() && mRecentsView.shouldShowOverviewActionsForState(state)
+ ? 1 : 0;
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
MultiValueAlpha.VALUE, overviewButtonAlpha, LINEAR);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index e075045..854a140 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -42,7 +42,7 @@
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.R)
-public class FallbackRecentsView extends RecentsView<RecentsActivity>
+public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
private RunningTaskInfo mHomeTaskInfo;
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index a9856d2..bbe279e 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -99,8 +99,8 @@
/**
* For this state, whether overview actions should be shown.
*/
- public boolean hasOverviewActions(RecentsActivity activity) {
- return hasFlag(FLAG_OVERVIEW_ACTIONS) && !showAsGrid(activity.getDeviceProfile());
+ public boolean hasOverviewActions() {
+ return hasFlag(FLAG_OVERVIEW_ACTIONS);
}
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 161e015..a1b7e01 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -36,9 +36,8 @@
Integer getTitleStringId() {
switch (mTutorialType) {
case RIGHT_EDGE_BACK_NAVIGATION:
- return R.string.back_gesture_tutorial_playground_title_swipe_inward_right_edge;
case LEFT_EDGE_BACK_NAVIGATION:
- return R.string.back_gesture_tutorial_playground_title_swipe_inward_left_edge;
+ return R.string.back_gesture_intro_title;
case BACK_NAVIGATION_COMPLETE:
return R.string.gesture_tutorial_confirm_title;
}
@@ -49,9 +48,8 @@
Integer getSubtitleStringId() {
switch (mTutorialType) {
case RIGHT_EDGE_BACK_NAVIGATION:
- return R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge;
case LEFT_EDGE_BACK_NAVIGATION:
- return R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge;
+ return R.string.back_gesture_intro_subtitle;
case BACK_NAVIGATION_COMPLETE:
return R.string.back_gesture_tutorial_confirm_subtitle;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 95352d1..fbf3a0a 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -38,7 +38,7 @@
Integer getTitleStringId() {
switch (mTutorialType) {
case HOME_NAVIGATION:
- return R.string.home_gesture_tutorial_playground_title;
+ return R.string.home_gesture_intro_title;
case HOME_NAVIGATION_COMPLETE:
return R.string.gesture_tutorial_confirm_title;
}
@@ -48,7 +48,7 @@
@Override
Integer getSubtitleStringId() {
if (mTutorialType == TutorialType.HOME_NAVIGATION) {
- return R.string.home_gesture_tutorial_playground_subtitle;
+ return R.string.home_gesture_intro_subtitle;
}
return null;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 45cbd0b..31f26d1 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -39,7 +39,7 @@
Integer getTitleStringId() {
switch (mTutorialType) {
case OVERVIEW_NAVIGATION:
- return R.string.overview_gesture_tutorial_playground_title;
+ return R.string.overview_gesture_intro_title;
case OVERVIEW_NAVIGATION_COMPLETE:
return R.string.gesture_tutorial_confirm_title;
}
@@ -49,7 +49,7 @@
@Override
Integer getSubtitleStringId() {
if (mTutorialType == TutorialType.OVERVIEW_NAVIGATION) {
- return R.string.overview_gesture_tutorial_playground_subtitle;
+ return R.string.overview_gesture_intro_subtitle;
}
return null;
}
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index f336bf5..b336d2f 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -80,7 +80,7 @@
SettingsCache mSettingsCache = SettingsCache.INSTANCE.get(context);
mSettingsCache.register(NOTIFICATION_BADGING_URI,
this::onNotificationDotsChanged);
- mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+ onNotificationDotsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
}
private static ArrayMap<String, LoggablePref> loadPrefKeys(Context context) {
diff --git a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
new file mode 100644
index 0000000..3730284
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.IAssistDataReceiver;
+import android.app.assist.AssistContent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.launcher3.util.Executors;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Can be used to request the AssistContent from a provided task id, useful for getting the web uri
+ * if provided from the task.
+ */
+public class AssistContentRequester {
+ private static final String TAG = "AssistContentRequester";
+ private static final String ASSIST_KEY_CONTENT = "content";
+
+ /** For receiving content, called on the main thread. */
+ public interface Callback {
+ /**
+ * Called when the {@link android.app.assist.AssistContent} of the requested task is
+ * available.
+ **/
+ void onAssistContentAvailable(AssistContent assistContent);
+ }
+
+ private final IActivityTaskManager mActivityTaskManager;
+ private final String mPackageName;
+ private final Executor mCallbackExecutor;
+
+ public AssistContentRequester(Context context) {
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mPackageName = context.getApplicationContext().getPackageName();
+ mCallbackExecutor = Executors.MAIN_EXECUTOR;
+ }
+
+ /**
+ * Request the {@link AssistContent} from the task with the provided id.
+ *
+ * @param taskId to query for the content.
+ * @param callback to call when the content is available, called on the main thread.
+ */
+ public void requestAssistContent(int taskId, Callback callback) {
+ try {
+ mActivityTaskManager.requestAssistDataForTask(
+ new AssistDataReceiver(callback, mCallbackExecutor), taskId, mPackageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
+ }
+ }
+
+ private static final class AssistDataReceiver extends IAssistDataReceiver.Stub {
+
+ private final Executor mExecutor;
+ private final Callback mCallback;
+
+ AssistDataReceiver(Callback callback, Executor callbackExecutor) {
+ mCallback = callback;
+ mExecutor = callbackExecutor;
+ }
+
+ @Override
+ public void onHandleAssistData(Bundle data) {
+ if (data == null) {
+ return;
+ }
+
+ final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
+ if (content == null) {
+ Log.e(TAG, "Received AssistData, but no AssistContent found");
+ return;
+ }
+
+ mExecutor.execute(() -> mCallback.onAssistContentAvailable(content));
+ }
+
+ @Override
+ public void onHandleAssistScreenshot(Bitmap screenshot) {}
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index 0f2d778..2285d74 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -19,9 +19,12 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.prediction.AppTarget;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -37,11 +40,13 @@
import android.graphics.RectF;
import android.net.Uri;
import android.util.Log;
+import android.view.View;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
import androidx.core.content.FileProvider;
+import com.android.internal.app.ChooserActivity;
import com.android.launcher3.BuildConfig;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
@@ -126,6 +131,22 @@
}
/**
+ * Launch the activity to share image with shared element transition.
+ */
+ @UiThread
+ public static void startShareActivity(Context context, Supplier<Bitmap> bitmapSupplier,
+ Rect crop, Intent intent, String tag, View sharedElement) {
+ if (bitmapSupplier.get() == null) {
+ Log.e(tag, "No snapshot available, not starting share.");
+ return;
+ }
+
+ UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(context,
+ bitmapSupplier.get(), crop, intent, ImageActionUtils::getShareIntentForImageUri,
+ tag, sharedElement));
+ }
+
+ /**
* Starts activity based on given intent created from image uri.
*/
@WorkerThread
@@ -142,6 +163,30 @@
}
/**
+ * Starts activity based on given intent created from image uri with shared element transition.
+ */
+ @WorkerThread
+ public static void persistBitmapAndStartActivity(Context context, Bitmap bitmap, Rect crop,
+ Intent intent, BiFunction<Uri, Intent, Intent[]> uriToIntentMap, String tag,
+ View scaledImage) {
+ Intent[] intents = uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent);
+
+ // Work around b/159412574
+ if (intents.length == 1) {
+ MAIN_EXECUTOR.execute(() -> context.startActivity(intents[0],
+ ActivityOptions.makeSceneTransitionAnimation((Activity) context, scaledImage,
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle()));
+
+ } else {
+ MAIN_EXECUTOR.execute(() -> context.startActivities(intents,
+ ActivityOptions.makeSceneTransitionAnimation((Activity) context, scaledImage,
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle()));
+ }
+ }
+
+
+
+ /**
* Converts image bitmap to Uri by temporarily saving bitmap to cache, and creating Uri pointing
* to that location. Used to be able to share an image with another app.
*
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index 3e87f48..2e5b33a 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -38,7 +38,8 @@
private static final String TAG = "InputConsumerProxy";
private final InputConsumerController mInputConsumerController;
- private final Supplier<InputConsumer> mConsumerSupplier;
+ private Runnable mCallback;
+ private Supplier<InputConsumer> mConsumerSupplier;
// The consumer is created lazily on demand.
private InputConsumer mInputConsumer;
@@ -48,8 +49,9 @@
private boolean mDestroyPending = false;
public InputConsumerProxy(InputConsumerController inputConsumerController,
- Supplier<InputConsumer> consumerSupplier) {
+ Runnable callback, Supplier<InputConsumer> consumerSupplier) {
mInputConsumerController = inputConsumerController;
+ mCallback = callback;
mConsumerSupplier = consumerSupplier;
}
@@ -64,9 +66,7 @@
if (ev instanceof MotionEvent) {
onInputConsumerMotionEvent((MotionEvent) ev);
} else if (ev instanceof KeyEvent) {
- if (mInputConsumer == null) {
- mInputConsumer = mConsumerSupplier.get();
- }
+ initInputConsumerIfNeeded();
mInputConsumer.onKeyEvent((KeyEvent) ev);
return true;
}
@@ -89,9 +89,7 @@
if (action == ACTION_DOWN) {
mTouchInProgress = true;
- if (mInputConsumer == null) {
- mInputConsumer = mConsumerSupplier.get();
- }
+ initInputConsumerIfNeeded();
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
@@ -115,4 +113,18 @@
mDestroyed = true;
mInputConsumerController.setInputListener(null);
}
+
+ public void unregisterCallback() {
+ mCallback = null;
+ }
+
+ private void initInputConsumerIfNeeded() {
+ if (mInputConsumer == null) {
+ if (mCallback != null) {
+ mCallback.run();
+ }
+ mInputConsumer = mConsumerSupplier.get();
+ mConsumerSupplier = null;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
new file mode 100644
index 0000000..8209c09
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+
+import java.util.function.Supplier;
+
+/**
+ * A factory that creates a input consumer for
+ * {@link com.android.quickstep.util.InputConsumerProxy}.
+ */
+public class InputProxyHandlerFactory implements Supplier<InputConsumer> {
+
+ private final BaseActivityInterface mActivityInterface;
+ private final GestureState mGestureState;
+
+ @UiThread
+ public InputProxyHandlerFactory(BaseActivityInterface activityInterface,
+ GestureState gestureState) {
+ mActivityInterface = activityInterface;
+ mGestureState = gestureState;
+ }
+
+ /**
+ * Called to create a input proxy for the running task
+ */
+ @Override
+ public InputConsumer get() {
+ StatefulActivity activity = mActivityInterface.getCreatedActivity();
+ return activity == null ? InputConsumer.NO_OP
+ : new OverviewInputConsumer(mGestureState, activity, null, true);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
index 60c7add..351adf4 100644
--- a/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
+++ b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
@@ -20,6 +20,8 @@
import android.content.Context;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.SysUINavigationMode;
import java.util.function.Predicate;
@@ -35,6 +37,7 @@
private final Supplier<Boolean> mBasePredicate;
private final Predicate<SysUINavigationMode.Mode> mModePredicate;
private boolean mSupported;
+ private OverviewComponentObserver mObserver;
private NavigationModeFeatureFlag(Supplier<Boolean> basePredicate,
Predicate<SysUINavigationMode.Mode> modePredicate) {
@@ -43,12 +46,16 @@
}
public boolean get() {
- return mBasePredicate.get() && mSupported;
+ return mBasePredicate.get() && mSupported && mObserver.isHomeAndOverviewSame();
}
public void initialize(Context context) {
onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context).getMode());
SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
+
+ // Temporary solution to disable live tile for the fallback launcher
+ RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(context);
+ mObserver = new OverviewComponentObserver(context, rads);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 1031c5b..1128dac 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -22,13 +22,11 @@
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -105,10 +103,6 @@
StateAnimationConfig config = new UseFirstInterpolatorStateAnimConfig();
config.duration = duration;
- config.animFlags = playStaggeredWorkspaceAnim
- // StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
- ? PLAY_ATOMIC_OVERVIEW_PEEK
- : ANIM_ALL_COMPONENTS;
boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler()
.isLayoutNaturalToLauncher();
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 1544f00..6d6e802 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -26,6 +26,7 @@
import android.content.SharedPreferences;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
@@ -63,7 +64,8 @@
});
}
- if (!hasReachedMaxCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
+ if (!Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && !hasReachedMaxCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
stateManager.addStateListener(new StateListener<LauncherState>() {
boolean mFromAllApps = false;
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index d4ca31f..6757e4c 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
@@ -60,7 +59,10 @@
public class StaggeredWorkspaceAnim {
private static final int APP_CLOSE_ROW_START_DELAY_MS = 10;
+ // How long it takes to fade in each staggered row.
private static final int ALPHA_DURATION_MS = 250;
+ // Should be used for animations running alongside this StaggeredWorkspaceAnim.
+ public static final int DURATION_MS = 250;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -131,15 +133,15 @@
}
if (animateOverviewScrim) {
- PendingAnimation pendingAnimation = new PendingAnimation(ALPHA_DURATION_MS);
+ PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS);
addScrimAnimationForState(launcher, NORMAL, pendingAnimation);
mAnimators.play(pendingAnimation.buildAnim());
}
- addDepthAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
+ addDepthAnimationForState(launcher, NORMAL, DURATION_MS);
mAnimators.play(launcher.getDragLayer().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
- .setDuration(ALPHA_DURATION_MS));
+ .setDuration(DURATION_MS));
mAnimators.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -181,7 +183,7 @@
*/
private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
StateAnimationConfig config = new StateAnimationConfig();
- config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
+ config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
config.duration = 0;
// setRecentsAttachedToAppWindow() will animate recents out.
launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 0a1a6e8..a1240e0 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -29,6 +29,7 @@
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
+import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -46,10 +47,12 @@
* Launcher and SysUI. Also, there should be one source of truth for the corner radius of the
* PiP window, which would ideally be on SysUI side as well.
*/
-public class SwipePipToHomeAnimator extends ValueAnimator implements
- ValueAnimator.AnimatorUpdateListener {
+public class SwipePipToHomeAnimator extends ValueAnimator {
private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
+ public static final float FRACTION_START = 0f;
+ public static final float FRACTION_END = 1f;
+
private final int mTaskId;
private final ComponentName mComponentName;
private final SurfaceControl mLeash;
@@ -139,7 +142,7 @@
mHasAnimationEnded = true;
}
});
- addUpdateListener(this);
+ addUpdateListener(this::onAnimationUpdate);
}
/** sets the from rotation if it's different from the target rotation. */
@@ -167,48 +170,53 @@
mAppBounds.top + mDestinationBounds.height());
}
- @Override
- public void onAnimationUpdate(ValueAnimator animator) {
+ private void onAnimationUpdate(ValueAnimator animator) {
if (mHasAnimationEnded) return;
-
- final float fraction = animator.getAnimatedFraction();
- final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
- mDestinationBoundsAnimation);
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
- if (mSourceHintRectInsets == null) {
- // no source rect hint been set, directly scale the window down
- onAnimationScale(fraction, tx, bounds);
- } else {
- // scale and crop according to the source rect hint
- onAnimationScaleAndCrop(fraction, tx, bounds);
- }
- mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash);
+ onAnimationUpdate(tx, animator.getAnimatedFraction());
tx.apply();
}
+ private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx,
+ float fraction) {
+ final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
+ mDestinationBoundsAnimation);
+ final PictureInPictureSurfaceTransaction op;
+ if (mSourceHintRectInsets == null) {
+ // no source rect hint been set, directly scale the window down
+ op = onAnimationScale(fraction, tx, bounds);
+ } else {
+ // scale and crop according to the source rect hint
+ op = onAnimationScaleAndCrop(fraction, tx, bounds);
+ }
+ return op;
+ }
+
/** scale the window directly with no source rect hint being set */
- private void onAnimationScale(float fraction, SurfaceControl.Transaction tx, Rect bounds) {
+ private PictureInPictureSurfaceTransaction onAnimationScale(
+ float fraction, SurfaceControl.Transaction tx, Rect bounds) {
if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
- mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
+ return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
} else {
- mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds);
+ return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds);
}
}
/** scale and crop the window with source rect hint */
- private void onAnimationScaleAndCrop(float fraction, SurfaceControl.Transaction tx,
+ private PictureInPictureSurfaceTransaction onAnimationScaleAndCrop(
+ float fraction, SurfaceControl.Transaction tx,
Rect bounds) {
final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
mSourceHintRectInsets);
if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
- mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
+ return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
} else {
- mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
+ return mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
}
}
@@ -224,34 +232,12 @@
return mDestinationBounds;
}
- /**
- * @return {@link Rect} of the final window crop in destination orientation.
- */
- public Rect getFinishWindowCrop() {
- final Rect windowCrop = new Rect(mAppBounds);
- if (mSourceHintRectInsets != null) {
- windowCrop.inset(mSourceHintRectInsets);
- }
- return windowCrop;
- }
-
- /**
- * @return Array of 9 floats represents the final transform in destination orientation.
- */
- public float[] getFinishTransform() {
- final Matrix transform = new Matrix();
- final float[] float9 = new float[9];
- if (mSourceHintRectInsets == null) {
- transform.setRectToRect(new RectF(mAppBounds), new RectF(mDestinationBounds),
- Matrix.ScaleToFit.FILL);
- } else {
- final float scale = mAppBounds.width() <= mAppBounds.height()
- ? (float) mDestinationBounds.width() / mAppBounds.width()
- : (float) mDestinationBounds.height() / mAppBounds.height();
- transform.setScale(scale, scale);
- }
- transform.getValues(float9);
- return float9;
+ /** @return {@link PictureInPictureSurfaceTransaction} for the final leash transaction. */
+ public PictureInPictureSurfaceTransaction getFinishTransaction() {
+ // get the final leash operations but do not apply to the leash.
+ final SurfaceControl.Transaction tx =
+ PipSurfaceTransactionHelper.newSurfaceControlTransaction();
+ return onAnimationUpdate(tx, FRACTION_END);
}
private RotatedPosition getRotatedPosition(float fraction) {
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 6cfe302..3c8a12c 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -330,8 +330,7 @@
Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
- .withCornerRadius(getCurrentCornerRadius())
- .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
+ .withCornerRadius(getCurrentCornerRadius());
if (LIVE_TILE.get() && params.getRecentsSurface() != null) {
// When relativeLayer = 0, it reverts the surfaces back to the original order.
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index cdf5163..756331d 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -57,7 +57,6 @@
private float mProgress;
private float mTargetAlpha;
private float mCornerRadius;
- private float mShadowRadius;
private RemoteAnimationTargets mTargetSet;
private SurfaceTransactionApplier mSyncTransactionApplier;
private SurfaceControl mRecentsSurface;
@@ -69,7 +68,6 @@
mProgress = 0;
mTargetAlpha = 1;
mCornerRadius = -1;
- mShadowRadius = 0;
}
/**
@@ -93,14 +91,6 @@
}
/**
- * Sets the shadow radius of the transformed window, in pixels.
- */
- public TransformParams setShadowRadius(float shadowRadius) {
- mShadowRadius = shadowRadius;
- return this;
- }
-
- /**
* Specifies the alpha of the transformed window. Default is 1.
*/
public TransformParams setTargetAlpha(float targetAlpha) {
@@ -207,10 +197,6 @@
return mCornerRadius;
}
- public float getShadowRadius() {
- return mShadowRadius;
- }
-
public SurfaceControl getRecentsSurface() {
return mRecentsSurface;
}
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
new file mode 100644
index 0000000..185080e5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.animation.Interpolator;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ScrimView;
+
+/**
+ * Scrim used for all-apps background. uses interpolator to coordinate fade in with
+ * all-apps contents
+ *
+ * Note: ranges are inverted because progress goes from 1 to 0 for NORMAL->AllAPPS
+ */
+public class AllAppsScrimView extends ScrimView<BaseQuickstepLauncher> {
+
+ private static final float TINT_DECAY_MULTIPLIER = .5f;
+
+ //min progress for scrim to become visible
+ private static final float SCRIM_VISIBLE_THRESHOLD = .9f;
+ //max progress where scrim alpha animates.
+ private static final float SCRIM_SOLID_THRESHOLD = .5f;
+ private final Interpolator mScrimInterpolator = Interpolators.clampToProgress(ACCEL,
+ SCRIM_SOLID_THRESHOLD,
+ SCRIM_VISIBLE_THRESHOLD);
+
+ // In transposed layout, we simply draw a flat color.
+ private boolean mDrawingFlatColor;
+
+ private final int mEndAlpha;
+ private final Paint mPaint;
+
+ private int mCurrentScrimColor;
+ private final int mTintColor;
+
+ public AllAppsScrimView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
+ mTintColor = Themes.getColorAccent(mContext);
+
+
+ mEndAlpha = Color.alpha(mEndScrim);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ // Just assume the easiest UI for now, until we have the proper layout information.
+ mDrawingFlatColor = true;
+ }
+
+ @Override
+ public void reInitUi() {
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ mDrawingFlatColor = dp.isVerticalBarLayout();
+ updateColors();
+ updateSysUiColors();
+ invalidate();
+ }
+
+ @Override
+ public void updateColors() {
+ super.updateColors();
+ if (mDrawingFlatColor) {
+ return;
+ }
+
+ if (mProgress >= 1) {
+ mCurrentScrimColor = 0;
+ } else {
+ float interpolationProgress = mScrimInterpolator.getInterpolation(mProgress);
+ // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
+ int alpha = Math.round(Utilities.mapRange(interpolationProgress, mEndAlpha, 0));
+ int color = ColorUtils.blendARGB(mEndScrim, mTintColor,
+ mProgress * TINT_DECAY_MULTIPLIER);
+ mCurrentScrimColor = setColorAlphaBound(color, alpha);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mDrawingFlatColor) {
+ if (mCurrentFlatColor != 0) {
+ canvas.drawColor(mCurrentFlatColor);
+ }
+ return;
+ }
+
+ if (Color.alpha(mCurrentScrimColor) == 0) {
+ return;
+ } else if (mProgress <= 0) {
+ canvas.drawColor(mCurrentScrimColor);
+ return;
+ }
+
+ mPaint.setColor(mCurrentScrimColor);
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 12b59d0..d616f7c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -45,14 +45,15 @@
private float mScrollAlpha = 1;
private float mContentAlpha = 1;
private float mVisibilityAlpha = 1;
+ private float mFullscreenProgress = 1;
private float mGridProgress = 1;
private boolean mIsRtl;
private float mNormalTranslationPrimary;
+ private float mFullscreenTranslationPrimary;
private float mGridTranslationPrimary;
- private float mGridTranslationSecondary;
private float mGridScrollOffset;
- private float mOffsetTranslationPrimary;
+ private float mScrollOffsetPrimary;
private int mSidePadding;
@@ -130,13 +131,13 @@
setClickable(Math.min(alpha, 1) == 1);
}
- public void setGridTranslationPrimary(float gridTranslationPrimary) {
- mGridTranslationPrimary = gridTranslationPrimary;
+ public void setFullscreenTranslationPrimary(float fullscreenTranslationPrimary) {
+ mFullscreenTranslationPrimary = fullscreenTranslationPrimary;
applyPrimaryTranslation();
}
- public void setGridTranslationSecondary(float gridTranslationSecondary) {
- mGridTranslationSecondary = gridTranslationSecondary;
+ public void setGridTranslationPrimary(float gridTranslationPrimary) {
+ mGridTranslationPrimary = gridTranslationPrimary;
applyPrimaryTranslation();
}
@@ -144,22 +145,34 @@
mGridScrollOffset = gridScrollOffset;
}
- public void setOffsetTranslationPrimary(float offsetTranslationPrimary) {
- mOffsetTranslationPrimary = offsetTranslationPrimary;
- applyPrimaryTranslation();
+ public void setScrollOffsetPrimary(float scrollOffsetPrimary) {
+ mScrollOffsetPrimary = scrollOffsetPrimary;
}
- public float getScrollAdjustment(boolean gridEnabled) {
+ public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
float scrollAdjustment = 0;
+ if (fullscreenEnabled) {
+ scrollAdjustment += mFullscreenTranslationPrimary;
+ }
if (gridEnabled) {
scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
}
- scrollAdjustment += mOffsetTranslationPrimary;
+ scrollAdjustment += mScrollOffsetPrimary;
return scrollAdjustment;
}
- public float getOffsetAdjustment(boolean gridEnabled) {
- return getScrollAdjustment(gridEnabled);
+ public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+ return getScrollAdjustment(fullscreenEnabled, gridEnabled);
+ }
+
+ /**
+ * Adjust translation when this TaskView is about to be shown fullscreen.
+ *
+ * @param progress: 0 = no translation; 1 = translate according to TaskVIew translations.
+ */
+ public void setFullscreenProgress(float progress) {
+ mFullscreenProgress = progress;
+ applyPrimaryTranslation();
}
/**
@@ -181,8 +194,8 @@
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
orientationHandler.getPrimaryViewTranslate().set(this,
orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
- + mNormalTranslationPrimary + mOffsetTranslationPrimary + getGridTrans(
- mGridTranslationPrimary));
+ + mNormalTranslationPrimary + getFullscreenTrans(
+ mFullscreenTranslationPrimary) + getGridTrans(mGridTranslationPrimary));
}
private void applySecondaryTranslation() {
@@ -193,8 +206,11 @@
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
orientationHandler.getSecondaryViewTranslate().set(this,
- orientationHandler.getSecondaryValue(0f, getOriginalTranslationY())
- + getGridTrans(mGridTranslationSecondary));
+ orientationHandler.getSecondaryValue(0f, getOriginalTranslationY()));
+ }
+
+ private float getFullscreenTrans(float endTranslation) {
+ return mFullscreenProgress > 0 ? endTranslation : 0;
}
private float getGridTrans(float endTranslation) {
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 25ae055..deb674c 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -30,6 +30,7 @@
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.AppUsageLimit;
import android.graphics.Outline;
+import android.graphics.Paint;
import android.icu.text.MeasureFormat;
import android.icu.text.MeasureFormat.FormatWidth;
import android.icu.util.Measure;
@@ -48,6 +49,7 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.systemui.shared.recents.model.Task;
import java.time.Duration;
@@ -297,4 +299,17 @@
mBanner.setAlpha(alpha);
}
}
+
+ void setBannerColorTint(int color, float amount) {
+ if (mBanner == null) {
+ return;
+ }
+ if (mBannerAlpha == 0 || amount == 0) {
+ mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ Paint layerPaint = new Paint();
+ layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
+ mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
+ mBanner.setLayerPaint(layerPaint);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 7cc00b7..5b0ade0 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -21,11 +21,7 @@
import android.util.AttributeSet;
import android.view.View;
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.FastBitmapDrawable;
-
-import java.util.ArrayList;
+import com.android.launcher3.Utilities;
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
@@ -33,14 +29,8 @@
*/
public class IconView extends View {
- public interface OnScaleUpdateListener {
- public void onScaleUpdate(float scale);
- }
-
private Drawable mDrawable;
- private ArrayList<OnScaleUpdateListener> mScaleListeners;
-
public IconView(Context context) {
super(context);
}
@@ -94,16 +84,6 @@
}
@Override
- public void invalidateDrawable(@NonNull Drawable drawable) {
- super.invalidateDrawable(drawable);
- if (drawable instanceof FastBitmapDrawable && mScaleListeners != null) {
- for (OnScaleUpdateListener listener : mScaleListeners) {
- listener.onScaleUpdate(((FastBitmapDrawable) drawable).getScale());
- }
- }
- }
-
- @Override
protected void onDraw(Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
@@ -115,22 +95,6 @@
return false;
}
- public void addUpdateScaleListener(OnScaleUpdateListener listener) {
- if (mScaleListeners == null) {
- mScaleListeners = new ArrayList<>();
- }
- mScaleListeners.add(listener);
- if (mDrawable instanceof FastBitmapDrawable) {
- listener.onScaleUpdate(((FastBitmapDrawable) mDrawable).getScale());
- }
- }
-
- public void removeUpdateScaleListener(OnScaleUpdateListener listener) {
- if (mScaleListeners != null) {
- mScaleListeners.remove(listener);
- }
- }
-
@Override
public void setAlpha(float alpha) {
super.setAlpha(alpha);
@@ -140,4 +104,16 @@
setVisibility(INVISIBLE);
}
}
+
+ /**
+ * Set the tint color of the icon, useful for scrimming or dimming.
+ *
+ * @param color to blend in.
+ * @param amount [0,1] 0 no tint, 1 full tint
+ */
+ public void setIconColorTint(int color, float amount) {
+ if (mDrawable != null) {
+ mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index a0af68a..896d1ae 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -19,11 +19,13 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
+import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import android.annotation.TargetApi;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -35,6 +37,7 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.systemui.plugins.PluginListener;
@@ -44,7 +47,7 @@
* {@link RecentsView} used in Launcher activity
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
+public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher, LauncherState>
implements StateListener<LauncherState> {
private RecentsExtraCard mRecentsExtraCardPlugin;
@@ -234,4 +237,33 @@
}
}
}
+
+ @Override
+ protected void onDismissAnimationEnds() {
+ super.onDismissAnimationEnds();
+ if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
+ // We want to keep the tasks translations in this temporary state
+ // after resetting the rest above
+ setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
+ setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
+ }
+ }
+
+ @Override
+ public void initiateSplitSelect(TaskView taskView,
+ SplitConfigurationOptions.SplitPositionOption splitPositionOption) {
+ super.initiateSplitSelect(taskView, splitPositionOption);
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // If overview is in modal state when rotate, reset it to overview state without running
+ // animation.
+ if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
+ resetModalVisuals();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 6fcd54c..9adeea4 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
import android.content.Context;
@@ -32,6 +33,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -76,6 +78,7 @@
private static final int INDEX_VISIBILITY_ALPHA = 1;
private static final int INDEX_FULLSCREEN_ALPHA = 2;
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
+ private static final int INDEX_SCROLL_ALPHA = 4;
private final MultiValueAlpha mMultiValueAlpha;
@@ -87,6 +90,9 @@
protected T mCallbacks;
+ private float mModalness;
+ private float mModalTransformY;
+
public OverviewActionsView(Context context) {
this(context, null);
}
@@ -97,7 +103,7 @@
public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr, 0);
- mMultiValueAlpha = new MultiValueAlpha(this, 4);
+ mMultiValueAlpha = new MultiValueAlpha(this, 5);
mMultiValueAlpha.setUpdateVisibility(true);
}
@@ -189,6 +195,10 @@
return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
}
+ public AlphaProperty getScrollAlpha() {
+ return mMultiValueAlpha.getProperty(INDEX_SCROLL_ALPHA);
+ }
+
private void updateHorizontalPadding() {
setPadding(mInsets.left, 0, mInsets.right, 0);
}
@@ -224,4 +234,27 @@
bottomMargin += mInsets.bottom;
return bottomMargin;
}
+
+ /**
+ * The current task is fully modal (modalness = 1) when it is shown on its own in a modal
+ * way. Modalness 0 means the task is shown in context with all the other tasks.
+ */
+ public void setTaskModalness(float modalness) {
+ mModalness = modalness;
+ applyTranslationY();
+ }
+
+ public void setModalTransformY(float modalTransformY) {
+ mModalTransformY = modalTransformY;
+ applyTranslationY();
+ }
+
+ private void applyTranslationY() {
+ setTranslationY(getModalTrans(mModalTransformY));
+ }
+
+ private float getModalTrans(float endTranslation) {
+ float progress = ACCEL_DEACCEL.getInterpolation(mModalness);
+ return Utilities.mapRange(progress, 0, endTranslation);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d357ebe..3c171fe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -25,8 +25,7 @@
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
-import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
+import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
@@ -34,6 +33,7 @@
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
@@ -50,6 +50,7 @@
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
@@ -61,6 +62,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -77,6 +79,7 @@
import android.util.FloatProperty;
import android.util.Log;
import android.util.SparseBooleanArray;
+import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -87,6 +90,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
import android.widget.ListView;
import androidx.annotation.Nullable;
@@ -96,7 +100,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -107,6 +110,7 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -129,8 +133,11 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
+import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.ViewUtils;
+import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.util.SurfaceTransactionApplier;
@@ -142,6 +149,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.wm.shell.pip.IPipAnimationListener;
@@ -152,8 +161,9 @@
* A list of recent tasks.
*/
@TargetApi(Build.VERSION_CODES.R)
-public abstract class RecentsView<T extends StatefulActivity> extends PagedView implements
- Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
+public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
+ STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
+ TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
SplitScreenBounds.OnChangeListener {
@@ -286,7 +296,7 @@
};
protected final RecentsOrientedState mOrientationState;
- protected final BaseActivityInterface mSizeStrategy;
+ protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
protected SurfaceTransactionApplier mSyncTransactionApplier;
protected int mTaskWidth;
@@ -295,6 +305,7 @@
protected final TaskViewSimulator mLiveTileTaskViewSimulator;
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
+ protected final Rect mLastComputedGridTaskSize = new Rect();
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
protected Float mLastComputedTaskPushOutDistance = null;
protected boolean mEnableDrawingLiveTile = false;
@@ -308,10 +319,11 @@
// The threshold at which we update the SystemUI flags when animating from the task into the app
public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
- protected final T mActivity;
+ protected final ACTIVITY_TYPE mActivity;
private final float mFastFlingVelocity;
private final RecentsModel mModel;
private final int mRowSpacing;
+ private final int mGridSideMargin;
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
@@ -338,14 +350,16 @@
private boolean mOverviewFullscreenEnabled;
private float mAdjacentPageOffset = 0;
- private float mTaskViewsSecondaryTranslation = 0;
- private float mTaskViewsPrimaryTranslation = 0;
+ protected float mTaskViewsSecondaryTranslation = 0;
+ protected float mTaskViewsPrimaryTranslation = 0;
// Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
private float mGridProgress = 0;
// The GestureEndTarget that is still in progress.
private GestureState.GestureEndTarget mCurrentGestureEndTarget;
+ IntSet mTopIdSet = new IntSet();
+
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
*/
@@ -425,9 +439,12 @@
protected int mRunningTaskId = -1;
protected boolean mRunningTaskTileHidden;
private Task mTmpRunningTask;
+ protected int mFocusedTaskId = -1;
+ private float mFocusedTaskRatio;
private boolean mRunningTaskIconScaledDown = false;
+ private final boolean mHasLightBackground;
private boolean mOverviewStateEnabled;
private boolean mHandleTaskStackChanges;
private boolean mSwipeDownShouldLaunchApp;
@@ -530,6 +547,7 @@
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
+ mGridSideMargin = getResources().getDimensionPixelSize(R.dimen.overview_grid_side_margin);
mSquaredTouchSlop = squaredTouchSlop(context);
mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
@@ -541,6 +559,7 @@
.getDimension(R.dimen.recents_empty_message_text_size));
mEmptyMessagePaint.setTypeface(Typeface.create(Themes.getDefaultBodyFont(context),
Typeface.NORMAL));
+ mEmptyMessagePaint.setAntiAlias(true);
mEmptyMessagePadding = getResources()
.getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
setWillNotDraw(false);
@@ -559,6 +578,8 @@
mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
+
+ mHasLightBackground = Themes.getAttrBoolean(mActivity, android.R.attr.isLightTheme);
}
public OverScroller getScroller() {
@@ -634,7 +655,6 @@
mActionsView = actionsView;
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
mSplitPlaceholderView = splitPlaceholderView;
-
}
public SplitPlaceholderView getSplitPlaceholder() {
@@ -715,6 +735,72 @@
super.draw(canvas);
}
+ public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
+ if (mRunningTaskId != -1 && mRunningTaskId == taskId &&
+ getLiveTileParams().getTargetSet().findTask(taskId) != null) {
+ launchSideTaskInLiveTileMode(taskId, getLiveTileParams().getTargetSet().apps);
+ }
+ }
+
+ public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
+ AnimatorSet anim = new AnimatorSet();
+ TaskView taskView = getTaskView(taskId);
+ if (taskView == null || !isTaskViewVisible(taskView)) {
+ // TODO: Refine this animation.
+ SurfaceTransactionApplier surfaceApplier =
+ new SurfaceTransactionApplier(mActivity.getDragLayer());
+ ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
+ appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
+ appAnimator.setInterpolator(ACCEL_DEACCEL);
+ appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+ @Override
+ public void onUpdate(float percent) {
+ SurfaceParams.Builder builder = new SurfaceParams.Builder(
+ apps[apps.length - 1].leash);
+ Matrix matrix = new Matrix();
+ matrix.postScale(percent, percent);
+ matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2,
+ mActivity.getDeviceProfile().heightPx * (1 - percent) / 2);
+ builder.withAlpha(percent).withMatrix(matrix);
+ surfaceApplier.scheduleApply(builder.build());
+ }
+ });
+ anim.play(appAnimator);
+ } else {
+ TaskViewUtils.composeRecentsLaunchAnimator(
+ anim, taskView, apps,
+ mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */,
+ mActivity.getStateManager(), this,
+ getDepthController());
+ }
+ anim.addListener(new AnimatorListenerAdapter(){
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ cleanUp(false);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ cleanUp(true);
+ }
+
+ private void cleanUp(boolean canceled) {
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ if (canceled) {
+ mRecentsAnimationController = null;
+ } else {
+ mSizeStrategy.onLaunchTaskSuccess();
+ }
+ ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
+ }
+ }
+ });
+ anim.start();
+ }
+
private void updateTaskStartIndex(View affectingView) {
if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) {
int childCount = getChildCount();
@@ -770,6 +856,13 @@
cancelSplitSelect(false);
}
}
+
+ if (enabled) {
+ mActivity.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, hasLightBackground());
+ } else {
+ mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+ }
}
public void onDigitalWellbeingToastShown() {
@@ -1042,6 +1135,7 @@
for (int i = 0; i < taskCount; i++) {
getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
}
+ mClearAllButton.setFullscreenProgress(fullscreenProgress);
// Fade out the actions view quickly (0.1 range)
mActionsView.getFullscreenAlpha().setValue(
@@ -1081,9 +1175,31 @@
mSizeStrategy.calculateGridSize(mActivity, mActivity.getDeviceProfile(),
mLastComputedGridSize);
+ mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
+ mLastComputedGridTaskSize, mOrientationHandler);
// Force TaskView to update size from thumbnail
updateTaskSize();
+
+ // Update ActionsView position
+ FrameLayout.LayoutParams layoutParams =
+ (FrameLayout.LayoutParams) mActionsView.getLayoutParams();
+ if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.bottomMargin =
+ dp.heightPx - mInsets.bottom - mLastComputedGridSize.bottom;
+ layoutParams.leftMargin = mLastComputedTaskSize.left;
+ layoutParams.rightMargin = dp.widthPx - mLastComputedTaskSize.right;
+ // When in modal state, remove bottom margin to avoid covering content.
+ mActionsView.setModalTransformY(layoutParams.bottomMargin);
+ } else {
+ layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ layoutParams.bottomMargin = 0;
+ layoutParams.leftMargin = 0;
+ layoutParams.rightMargin = 0;
+ mActionsView.setModalTransformY(0);
+ }
+ mActionsView.setLayoutParams(layoutParams);
}
/**
@@ -1115,7 +1231,6 @@
// Compensate page spacing widening caused by RecentsView scaling.
widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale);
float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff;
- fullscreenTranslations[i] += fullscreenTranslationX;
accumulatedTranslationX += fullscreenTranslationX;
}
@@ -1125,8 +1240,15 @@
getTaskViewAt(i).setFullscreenTranslationX(
fullscreenTranslations[i] - fullscreenTranslations[firstNonHomeTaskIndex]);
}
+ mClearAllButton.setFullscreenTranslationPrimary(
+ accumulatedTranslationX - fullscreenTranslations[firstNonHomeTaskIndex]);
- updateGridProperties();
+ // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
+ // TaskViews.
+ int clearAllWidthDiff = mTaskWidth - mClearAllButton.getWidth();
+ mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
+
+ updateGridProperties(false);
}
public void getTaskSize(Rect outRect) {
@@ -1135,11 +1257,36 @@
mLastComputedTaskSize.set(outRect);
}
+ /**
+ * Returns the size of task selected to enter modal state.
+ */
+ public Point getSelectedTaskSize() {
+ mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), mTempRect,
+ mOrientationHandler);
+ int taskWidth = mTempRect.width();
+ int taskHeight = mTempRect.height();
+ if (mRunningTaskId != -1) {
+ int boxLength = Math.max(taskWidth, taskHeight);
+ if (mFocusedTaskRatio > 1) {
+ taskWidth = boxLength;
+ taskHeight = (int) (boxLength / mFocusedTaskRatio);
+ } else {
+ taskWidth = (int) (boxLength * mFocusedTaskRatio);
+ taskHeight = boxLength;
+ }
+ }
+ return new Point(taskWidth, taskHeight);
+ }
+
/** Gets the last computed task size */
public Rect getLastComputedTaskSize() {
return mLastComputedTaskSize;
}
+ public Rect getLastComputedGridTaskSize() {
+ return mLastComputedGridTaskSize;
+ }
+
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
@@ -1158,6 +1305,15 @@
// After scrolling, update the visible task's data
loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
+
+ // After scrolling, update ActionsView's visibility.
+ TaskView focusedTaskView = getFocusedTaskView();
+ if (focusedTaskView != null) {
+ float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
+ - mOrientationHandler.getPrimaryScroll(this));
+ float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
+ mActionsView.getScrollAlpha().setValue(Utilities.boundToRange(delta, 0, 1));
+ }
}
// Update the high res thumbnail loader state
@@ -1322,6 +1478,7 @@
setCurrentTask(-1);
mIgnoreResetTaskId = -1;
mTaskListChangeId = -1;
+ mFocusedTaskId = -1;
mRecentsAnimationController = null;
mLiveTileParams.setTargetSet(null);
@@ -1348,6 +1505,17 @@
return getTaskIndexForId(mRunningTaskId);
}
+ public @Nullable TaskView getFocusedTaskView() {
+ return getTaskView(mFocusedTaskId);
+ }
+
+ /**
+ * Returns the width to height ratio of the focused {@link TaskView}.
+ */
+ public float getFocusedTaskRatio() {
+ return mFocusedTaskRatio;
+ }
+
/**
* Get the index of the task view whose id matches {@param taskId}.
* @return -1 if there is no task view for the task id, else the index of the task view.
@@ -1439,6 +1607,11 @@
*/
public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
mCurrentGestureEndTarget = endTarget;
+ if (showAsGrid()) {
+ mFocusedTaskId = mRunningTaskId;
+ mFocusedTaskRatio =
+ mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
+ }
}
/**
@@ -1459,8 +1632,7 @@
setRunningTaskHidden(false);
animateUpRunningTaskIconScale();
- // TODO: This should be tied to whether there is a focus app on overview.
- if (!showAsGrid()) {
+ if (!showAsGrid() || getFocusedTaskView() != null) {
animateActionsViewIn();
}
@@ -1580,6 +1752,13 @@
anim.start();
}
+ private void animateActionsViewOut() {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(
+ mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 1, 0);
+ anim.setDuration(TaskView.SCALE_ICON_DURATION);
+ anim.start();
+ }
+
public void animateUpRunningTaskIconScale() {
animateUpRunningTaskIconScale(0);
}
@@ -1599,14 +1778,18 @@
* This method only calculates the potential position and depends on {@link #setGridProgress} to
* apply the actual scaling and translation.
*/
- private void updateGridProperties() {
+ private void updateGridProperties(boolean isTaskDismissal) {
int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
}
- final int boxLength = Math.max(mTaskWidth, mTaskHeight);
+ final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
+ mLastComputedGridTaskSize.height());
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
+ float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
+
int topRowWidth = 0;
int bottomRowWidth = 0;
float topAccumulatedTranslationX = 0;
@@ -1615,6 +1798,10 @@
IntSet bottomSet = new IntSet();
float[] gridTranslations = new float[taskCount];
int firstNonHomeTaskIndex = 0;
+
+ if (!isTaskDismissal) {
+ mTopIdSet.clear();
+ }
for (int i = 0; i < taskCount; i++) {
TaskView taskView = getTaskViewAt(i);
if (isHomeTask(taskView)) {
@@ -1624,12 +1811,24 @@
continue;
}
- if (topRowWidth <= bottomRowWidth) {
+ // Evenly distribute tasks between rows unless rearranging due to task dismissal, in
+ // which case keep tasks in their respective rows. For the running task, don't join
+ // the grid.
+ if (taskView.isRunningTask()) {
+ topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
+ bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
+
+ // Center view vertically in case it's from different orientation.
+ taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
+ - taskView.getLayoutParams().height) / 2f);
+ } else if ((!isTaskDismissal && topRowWidth <= bottomRowWidth) || (isTaskDismissal
+ && mTopIdSet.contains(taskView.getTask().key.id))) {
gridTranslations[i] += topAccumulatedTranslationX;
topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
topSet.add(i);
+ mTopIdSet.add(taskView.getTask().key.id);
- taskView.setGridTranslationY(0);
+ taskView.setGridTranslationY(taskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
@@ -1646,8 +1845,7 @@
bottomSet.add(i);
// Move into bottom row.
- float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
- taskView.setGridTranslationY(heightOffset);
+ taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
@@ -1661,20 +1859,12 @@
}
}
- // If the first non-home task does not take full width of task Rect, shift all tasks
- // accordingly without affecting scrolls.
- int firstTaskWidth = getTaskViewAt(firstNonHomeTaskIndex).getLayoutParams().width;
- float firstNonHomeTaskOffset = firstTaskWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 0
- : mTaskWidth - firstTaskWidth;
- float offsetTranslation = mIsRtl ? firstNonHomeTaskOffset : -firstNonHomeTaskOffset;
-
// We need to maintain first non-home task's grid translation at 0, now shift translation
// of all the TaskViews to achieve that.
for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
TaskView taskView = getTaskViewAt(i);
taskView.setGridTranslationX(
gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
- taskView.setGridOffsetTranslationX(offsetTranslation);
}
// Use the accumulated translation of the longer row.
@@ -1713,12 +1903,9 @@
mClearAllButton.setGridTranslationPrimary(
clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
- mClearAllButton.setGridTranslationSecondary(
- boxLength - mTaskHeight / 2f + mRowSpacing / 2f);
mClearAllButton.setGridScrollOffset(
mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
: mLastComputedTaskSize.right - mLastComputedGridSize.right);
- mClearAllButton.setOffsetTranslationPrimary(offsetTranslation);
setGridProgress(mGridProgress);
}
@@ -1991,25 +2178,26 @@
} else {
snapToPageImmediately(pageToSnapTo);
// Grid got messed up, reapply.
- updateGridProperties();
+ updateGridProperties(true);
+ if (showAsGrid() && getFocusedTaskView() == null) {
+ animateActionsViewOut();
+ }
}
// Update the layout synchronously so that the position of next view is
// immediately available.
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
}
resetTaskVisuals();
- if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
- // We want to keep the tasks translations in this temporary state
- // after resetting the rest above
- setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
- setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
- }
+ onDismissAnimationEnds();
mPendingAnimation = null;
}
});
return anim;
}
+ protected void onDismissAnimationEnds() {
+ }
+
public PendingAnimation createAllTasksDismissAnimation(long duration) {
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
@@ -2177,13 +2365,6 @@
if (mOrientationState.setRecentsRotation(rotation)) {
updateOrientationHandler();
}
-
- // If overview is in modal state when rotate, reset it to overview state without running
- // animation.
- if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
- mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
- resetModalVisuals();
- }
}
public void setLayoutRotation(int touchRotation, int displayRotation) {
@@ -2395,7 +2576,7 @@
return distanceToOffscreen * offsetProgress;
}
- private void setTaskViewsResistanceTranslation(float translation) {
+ protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView task = getTaskViewAt(i);
@@ -2404,7 +2585,7 @@
mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
}
- private void setTaskViewsPrimaryTranslation(float translation) {
+ protected void setTaskViewsPrimaryTranslation(float translation) {
mTaskViewsPrimaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView task = getTaskViewAt(i);
@@ -2430,12 +2611,19 @@
}
}
+ /**
+ * True if the background scrim of the recents view is light colored and the foreground elements
+ * should use dark colors.
+ */
+ public boolean hasLightBackground() {
+ return mHasLightBackground;
+ }
+
public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
mSplitHiddenTaskView = taskView;
mSplitPlaceholderView.getSplitController().setInitialTaskSelect(taskView,
splitPositionOption);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
- mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
}
public PendingAnimation createSplitSelectInitAnimation() {
@@ -2674,10 +2862,13 @@
progressAnim.addUpdateListener(animator -> {
// Once we pass a certain threshold, update the sysui flags to match the target
// tasks' flags
- mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW,
- animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD
- ? targetSysUiFlags
- : 0);
+ if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+ mActivity.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, targetSysUiFlags);
+ } else {
+ mActivity.getSystemUiController().updateUiState(
+ UI_STATE_OVERVIEW, hasLightBackground());
+ }
// Passing the threshold from taskview to fullscreen app will vibrate
final boolean passed = animator.getAnimatedFraction() >=
@@ -2863,10 +3054,7 @@
* Returns page scroll of the left most child.
*/
public int getLeftMostChildScroll() {
- if (mIsRtl) {
- return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
- }
- return getScrollForPage(mTaskViewStartIndex);
+ return getScrollForPage(mIsRtl ? indexOfChild(mClearAllButton) : mTaskViewStartIndex);
}
@Override
@@ -2877,10 +3065,7 @@
// so use the rightmost task as the min scroll.
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
- if (mIsRtl) {
- return getScrollForPage(mTaskViewStartIndex);
- }
- return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+ return getScrollForPage(mIsRtl ? mTaskViewStartIndex : indexOfChild(mClearAllButton));
}
return super.computeMaxScroll();
}
@@ -2899,7 +3084,8 @@
scrollDiff = ((TaskView) child).getScrollAdjustment(mOverviewFullscreenEnabled,
showAsGrid());
} else if (child instanceof ClearAllButton) {
- scrollDiff = ((ClearAllButton) child).getScrollAdjustment(showAsGrid());
+ scrollDiff = ((ClearAllButton) child).getScrollAdjustment(
+ mOverviewFullscreenEnabled, showAsGrid());
}
if (scrollDiff != 0) {
@@ -2918,7 +3104,8 @@
childOffset += ((TaskView) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
showAsGrid());
} else if (child instanceof ClearAllButton) {
- childOffset += ((ClearAllButton) child).getOffsetAdjustment(showAsGrid());
+ childOffset += ((ClearAllButton) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
+ showAsGrid());
}
return childOffset;
}
@@ -3094,6 +3281,7 @@
boolean inPlaceLandscape = !mOrientationState.canRecentsActivityRotate()
&& mOrientationState.getTouchRotation() != ROTATION_0;
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape);
+ mActionsView.setTaskModalness(modalness);
}
@Nullable
@@ -3122,12 +3310,27 @@
return mSizeStrategy;
}
+ /**
+ * Set all the task views to color tint scrim mode, dimming or tinting them all. Allows the
+ * tasks to be dimmed while other elements in the recents view are left alone.
+ */
+ public void showForegroundScrim(boolean show) {
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ getTaskViewAt(i).showColorTint(show);
+ }
+ }
+
private boolean showAsGrid() {
return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
&& mSizeStrategy.stateFromGestureEndTarget(
mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
}
+ public boolean shouldShowOverviewActionsForState(STATE_TYPE state) {
+ return !state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())
+ || getFocusedTaskView() != null;
+ }
+
/**
* Used to register callbacks for when our empty message state changes.
*
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
deleted file mode 100644
index db04fc0..0000000
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.views;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Path.Direction;
-import android.graphics.Path.Op;
-import android.util.AttributeSet;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.uioverrides.states.OverviewState;
-import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
-
-/**
- * Scrim used for all-apps and shelf in Overview
- * In transposed layout, it behaves as a simple color scrim.
- * In portrait layout, it draws a rounded rect such that
- * From normal state to overview state, the shelf just fades in and does not move
- * From overview state to all-apps state the shelf moves up and fades in to cover the screen
- */
-public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
- implements NavigationModeChangeListener {
-
- // If the progress is more than this, shelf follows the finger, otherwise it moves faster to
- // cover the whole screen
- private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
-
- // Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public
- private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f;
-
- // In transposed layout, we simply draw a flat color.
- private boolean mDrawingFlatColor;
-
- // For shelf mode
- private final int mEndAlpha;
- private final float mRadius;
- private final int mMaxScrimAlpha;
- private final Paint mPaint;
-
- // Mid point where the alpha changes
- private int mMidAlpha;
- private float mMidProgress;
-
- private Interpolator mBeforeMidProgressColorInterpolator = ACCEL;
- private Interpolator mAfterMidProgressColorInterpolator = ACCEL;
-
- private float mShiftRange;
-
- private float mTopOffset;
- private float mShelfTop;
- private float mShelfTopAtThreshold;
-
- private int mShelfColor;
- private int mRemainingScreenColor;
-
- private final Path mTempPath = new Path();
- private final Path mRemainingScreenPath = new Path();
- private boolean mRemainingScreenPathValid = false;
-
- private Mode mSysUINavigationMode;
-
- public ShelfScrimView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
-
- mEndAlpha = Color.alpha(mEndScrim);
- mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- // Just assume the easiest UI for now, until we have the proper layout information.
- mDrawingFlatColor = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mRemainingScreenPathValid = false;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(getContext())
- .addModeChangeListener(this));
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- SysUINavigationMode.INSTANCE.get(getContext()).removeModeChangeListener(this);
- }
-
- @Override
- public void onNavigationModeChanged(Mode newMode) {
- mSysUINavigationMode = newMode;
- // Note that these interpolators are inverted because progress goes 1 to 0.
- if (mSysUINavigationMode == Mode.NO_BUTTON) {
- // Show the shelf more quickly before reaching overview progress.
- mBeforeMidProgressColorInterpolator = ACCEL_2;
- mAfterMidProgressColorInterpolator = ACCEL;
- } else {
- mBeforeMidProgressColorInterpolator = ACCEL;
- mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
- }
- }
-
- @Override
- public void reInitUi() {
- DeviceProfile dp = mLauncher.getDeviceProfile();
- mDrawingFlatColor = dp.isVerticalBarLayout();
-
- if (!mDrawingFlatColor) {
- mRemainingScreenPathValid = false;
- mShiftRange = mLauncher.getAllAppsController().getShiftRange();
-
- // Fade in all apps background quickly to distinguish from swiping from nav bar.
- mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
- mMidProgress = 1 - (OverviewState.getDefaultSwipeHeight(mLauncher)
- / mLauncher.getAllAppsController().getShiftRange());
-
- mTopOffset = dp.getInsets().top;
- mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
- }
- updateColors();
- updateSysUiColors();
- invalidate();
- }
-
- @Override
- public void updateColors() {
- super.updateColors();
- if (mDrawingFlatColor) {
- return;
- }
-
- if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
- mShelfTop = mShiftRange * mProgress + mTopOffset;
- } else {
- mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
- mShelfTopAtThreshold);
- }
-
- if (mProgress >= 1) {
- mRemainingScreenColor = 0;
- mShelfColor = 0;
- } else if (mProgress >= mMidProgress) {
- mRemainingScreenColor = 0;
-
- int alpha = Math.round(Utilities.mapToRange(
- mProgress, mMidProgress, 1, mMidAlpha, 0, mBeforeMidProgressColorInterpolator));
- mShelfColor = setColorAlphaBound(mEndScrim, alpha);
- } else {
- // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
- int alpha = Math.round(
- Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
- (float) mMidAlpha, mAfterMidProgressColorInterpolator));
- mShelfColor = setColorAlphaBound(mEndScrim, alpha);
-
- int remainingScrimAlpha = Math.round(
- Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
- (float) 0, LINEAR));
- mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
- }
- }
-
- @Override
- protected void updateSysUiColors() {
- if (mDrawingFlatColor) {
- super.updateSysUiColors();
- } else {
- // Use a light system UI (dark icons) if all apps is behind at least half of the
- // status bar.
- boolean forceChange = mShelfTop <= mLauncher.getDeviceProfile().getInsets().top / 2f;
- if (forceChange) {
- mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
- } else {
- mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
- }
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mDrawingFlatColor) {
- if (mCurrentFlatColor != 0) {
- canvas.drawColor(mCurrentFlatColor);
- }
- return;
- }
-
- if (Color.alpha(mShelfColor) == 0) {
- return;
- } else if (mProgress <= 0) {
- canvas.drawColor(mShelfColor);
- return;
- }
-
- int height = getHeight();
- int width = getWidth();
- // Draw the scrim over the remaining screen if needed.
- if (mRemainingScreenColor != 0) {
- if (!mRemainingScreenPathValid) {
- mTempPath.reset();
- // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
- // corners due to rounding issues.
- mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10,
- mRadius, mRadius, Direction.CW);
- mRemainingScreenPath.reset();
- mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
- mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
- }
-
- float offset = height - mRadius - mShelfTop;
- canvas.translate(0, -offset);
- mPaint.setColor(mRemainingScreenColor);
- canvas.drawPath(mRemainingScreenPath, mPaint);
- canvas.translate(0, offset);
- }
-
- mPaint.setColor(mShelfColor);
- canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index a46daf3..0b84bc9 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -249,9 +249,11 @@
final Animator revealAnimator = createOpenCloseOutlineProvider()
.createRevealAnimator(this, closing);
revealAnimator.setInterpolator(Interpolators.DEACCEL);
- mOpenCloseAnimator.play(revealAnimator);
- mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA,
- closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
+ mOpenCloseAnimator.playTogether(revealAnimator,
+ ObjectAnimator.ofFloat(
+ mTaskView.getThumbnail(), DIM_ALPHA,
+ closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
+ ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
@@ -265,7 +267,6 @@
}
}
});
- mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION);
mOpenCloseAnimator.start();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index af62582..685f725 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -28,8 +28,6 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -46,10 +44,10 @@
import android.view.View;
import androidx.annotation.RequiresApi;
+import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -67,10 +65,6 @@
* A task in the Recents view.
*/
public class TaskThumbnailView extends View implements PluginListener<OverviewScreenshotActions> {
-
- private static final ColorMatrix COLOR_MATRIX = new ColorMatrix();
- private static final ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
-
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
@@ -89,11 +83,11 @@
private final BaseActivity mActivity;
private TaskOverlay mOverlay;
- private final boolean mIsDarkTextTheme;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
+ private final int mDimColor;
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
@@ -104,9 +98,8 @@
private ThumbnailData mThumbnailData;
protected BitmapShader mBitmapShader;
- private float mDimAlpha = 1f;
- private float mDimAlphaMultiplier = 1f;
- private float mSaturation = 1f;
+ /** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
+ private float mDimAlpha = 0f;
private boolean mOverlayEnabled;
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
@@ -124,11 +117,12 @@
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
- mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
- mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
// Initialize with placeholder value. It is overridden later by TaskView
mFullscreenParams = TEMP_PARAMS.get(context);
+
+ mDimColor = Themes.getColorBackgroundFloating(context);
+ mDimmingPaintAfterClearing.setColor(mDimColor);
}
/**
@@ -186,15 +180,12 @@
updateThumbnailPaintFilter();
}
- public void setDimAlphaMultipler(float dimAlphaMultipler) {
- mDimAlphaMultiplier = dimAlphaMultipler;
- setDimAlpha(mDimAlpha);
- }
-
/**
* Sets the alpha of the dim layer on top of this view.
* <p>
- * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black.
+ * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
+ * extracted background color.
+ *
*/
public void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
@@ -359,15 +350,15 @@
}
private void updateThumbnailPaintFilter() {
- int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255);
- ColorFilter filter = getColorFilter(mul, mIsDarkTextTheme, mSaturation);
+ ColorFilter filter = getColorFilter(mDimAlpha);
mBackgroundPaint.setColorFilter(filter);
- mDimmingPaintAfterClearing.setAlpha(255 - mul);
+ int alpha = (int) (mDimAlpha * 255);
+ mDimmingPaintAfterClearing.setAlpha(alpha);
if (mBitmapShader != null) {
mPaint.setColorFilter(filter);
} else {
mPaint.setColorFilter(null);
- mPaint.setColor(Color.argb(255, mul, mul, mul));
+ mPaint.setColor(ColorUtils.blendARGB(Color.BLACK, mDimColor, alpha));
}
invalidate();
}
@@ -401,35 +392,8 @@
updateThumbnailMatrix();
}
- /**
- * @param intensity multiplier for color values. 0 - make black (white if shouldLighten), 255 -
- * leave unchanged.
- */
- private static ColorFilter getColorFilter(int intensity, boolean shouldLighten,
- float saturation) {
- intensity = Utilities.boundToRange(intensity, 0, 255);
-
- if (intensity == 255 && saturation == 1) {
- return null;
- }
-
- final float intensityScale = intensity / 255f;
- COLOR_MATRIX.setScale(intensityScale, intensityScale, intensityScale, 1);
-
- if (saturation != 1) {
- SATURATION_COLOR_MATRIX.setSaturation(saturation);
- COLOR_MATRIX.postConcat(SATURATION_COLOR_MATRIX);
- }
-
- if (shouldLighten) {
- final float[] colorArray = COLOR_MATRIX.getArray();
- final int colorAdd = 255 - intensity;
- colorArray[4] = colorAdd;
- colorArray[9] = colorAdd;
- colorArray[14] = colorAdd;
- }
-
- return new ColorMatrixColorFilter(COLOR_MATRIX);
+ private ColorFilter getColorFilter(float dimAmount) {
+ return Utilities.makeColorTintingColorFilter(mDimColor, dimAmount);
}
public Bitmap getThumbnail() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index d497a96..e78406f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -89,6 +89,7 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.launcher3.util.ViewPool.Reusable;
import com.android.quickstep.RecentsModel;
@@ -134,10 +135,7 @@
@IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
public @interface TaskDataChanges {}
- /**
- * The alpha of a black scrim on a page in the carousel as it leaves the screen.
- * In the resting position of the carousel, the adjacent pages have about half this scrim.
- */
+ /** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
/**
@@ -254,6 +252,19 @@
}
};
+ private static final FloatProperty<TaskView> COLOR_TINT =
+ new FloatProperty<TaskView>("colorTint") {
+ @Override
+ public void setValue(TaskView taskView, float v) {
+ taskView.setColorTint(v);
+ }
+
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.getColorTint();
+ }
+ };
+
private final OnAttachStateChangeListener mTaskMenuStateListener =
new OnAttachStateChangeListener() {
@Override
@@ -295,8 +306,6 @@
// The following grid translations scales with mGridProgress.
private float mGridTranslationX;
private float mGridTranslationY;
- // Offset translation does not affect scroll calculation.
- private float mGridOffsetTranslationX;
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
@@ -316,6 +325,11 @@
private final float[] mIconCenterCoords = new float[2];
private final float[] mChipCenterCoords = new float[2];
+ // Colored tint for the task view and all its supplementary views (like the task icon and well
+ // being banner.
+ private final int mTintingColor;
+ private float mTintAmount;
+
private boolean mIsClickableAsLiveTile = true;
public TaskView(Context context) {
@@ -377,6 +391,8 @@
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
setOutlineProvider(mOutlineProvider);
+
+ mTintingColor = Themes.getColorBackgroundFloating(context);
}
/**
@@ -724,7 +740,6 @@
progress = 1 - progress;
}
mFocusTransitionProgress = progress;
- mSnapshotView.setDimAlphaMultipler(0);
float iconScalePercentage = (float) SCALE_ICON_DURATION / DIM_ANIM_DURATION;
float lowerClamp = invert ? 1f - iconScalePercentage : 0;
float upperClamp = invert ? 1 : iconScalePercentage;
@@ -783,6 +798,7 @@
setTranslationZ(0);
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
+ setColorTint(0);
}
public void setStableAlpha(float parentAlpha) {
@@ -792,8 +808,7 @@
@Override
public void onRecycle() {
- mFullscreenTranslationX = mGridTranslationX =
- mGridTranslationY = mGridOffsetTranslationX = mBoxTranslationY = 0f;
+ mFullscreenTranslationX = mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
resetViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
@@ -874,7 +889,7 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
- setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? (right - left) : 0);
+ setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
setPivotY(mSnapshotView.getTop());
} else {
setPivotX((right - left) * 0.5f);
@@ -979,11 +994,6 @@
return mGridTranslationY;
}
- public void setGridOffsetTranslationX(float gridOffsetTranslationX) {
- mGridOffsetTranslationX = gridOffsetTranslationX;
- applyTranslationX();
- }
-
public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
float scrollAdjustment = 0;
if (fullscreenEnabled) {
@@ -995,12 +1005,8 @@
return scrollAdjustment;
}
- public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) {
- float offsetAdjustment = getScrollAdjustment(fullscreenEnabled, gridEnabled);
- if (gridEnabled) {
- offsetAdjustment += mGridOffsetTranslationX;
- }
- return offsetAdjustment;
+ public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+ return getScrollAdjustment(fullscreenEnabled, gridEnabled);
}
public float getSizeAdjustment(boolean fullscreenEnabled) {
@@ -1019,7 +1025,7 @@
private void applyTranslationX() {
setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
+ getFullscreenTrans(mFullscreenTranslationX)
- + getGridTrans(mGridTranslationX + mGridOffsetTranslationX));
+ + getGridTrans(mGridTranslationX));
}
private void applyTranslationY() {
@@ -1225,62 +1231,77 @@
*/
void updateTaskSize() {
ViewGroup.LayoutParams params = getLayoutParams();
+ float fullscreenScale;
+ float boxTranslationY;
+ int expectedWidth;
+ int expectedHeight;
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
final int thumbnailPadding =
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
+ final int taskWidth = lastComputedTaskSize.width();
+ final int taskHeight = lastComputedTaskSize.height();
- Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
- int taskWidth = lastComputedTaskSize.width();
- int taskHeight = lastComputedTaskSize.height();
-
- int expectedWidth;
- int expectedHeight;
- float thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio(
- TaskView.CLIP_STATUS_AND_NAV_BARS) : 0f;
- if (isRunningTask() || thumbnailRatio == 0f) {
- expectedWidth = taskWidth;
- expectedHeight = taskHeight + thumbnailPadding;
+ int boxWidth;
+ int boxHeight;
+ float thumbnailRatio;
+ boolean isFocusedTask = isFocusedTask();
+ if (isFocusedTask || isRunningTask()) {
+ // Task will be focused and should use focused task size. Use runningTaskRatio
+ // that is associated with the original orientation of the focused task if possible.
+ boxWidth = taskWidth;
+ boxHeight = taskHeight;
+ thumbnailRatio = isFocusedTask ? getRecentsView().getFocusedTaskRatio() : 0;
} else {
- int boxLength = Math.max(taskWidth, taskHeight);
- if (thumbnailRatio > 1) {
- expectedWidth = boxLength;
- expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
- } else {
- expectedWidth = (int) (boxLength * thumbnailRatio);
- expectedHeight = boxLength + thumbnailPadding;
- }
+ // Otherwise task is in grid, and should use lastComputedGridTaskSize.
+ Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
+ boxWidth = lastComputedGridTaskSize.width();
+ boxHeight = lastComputedGridTaskSize.height();
+ thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio(
+ TaskView.CLIP_STATUS_AND_NAV_BARS) : 0f;
+ }
+ int boxLength = Math.max(boxWidth, boxHeight);
+
+ // Bound width/height to the box size.
+ if (thumbnailRatio == 0f) {
+ expectedWidth = boxWidth;
+ expectedHeight = boxHeight + thumbnailPadding;
+ } else if (thumbnailRatio > 1) {
+ expectedWidth = boxLength;
+ expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
+ } else {
+ expectedWidth = (int) (boxLength * thumbnailRatio);
+ expectedHeight = boxLength + thumbnailPadding;
}
- float heightDiff = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
- setBoxTranslationY(heightDiff);
+ // Scale to to fit task Rect.
+ fullscreenScale = taskWidth / (float) boxWidth;
- float fullscreenScale = 1f;
- if (expectedWidth > taskWidth) {
- // In full screen, expectedWidth should not be larger than taskWidth.
- fullscreenScale = taskWidth / (float) expectedWidth;
- } else if (expectedHeight - thumbnailPadding > taskHeight) {
- // In full screen, expectedHeight should not be larger than taskHeight.
- fullscreenScale = taskHeight / (float) (expectedHeight - thumbnailPadding);
+ // In full screen, scale back TaskView to original size.
+ if (expectedWidth > boxWidth) {
+ fullscreenScale *= boxWidth / (float) expectedWidth;
+ } else if (expectedHeight - thumbnailPadding > boxHeight) {
+ fullscreenScale *= boxHeight / (float) (expectedHeight - thumbnailPadding);
}
- setFullscreenScale(fullscreenScale);
- if (params.width != expectedWidth || params.height != expectedHeight) {
- params.width = expectedWidth;
- params.height = expectedHeight;
- setLayoutParams(params);
- }
+ // Align to top of task Rect.
+ boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
} else {
- setBoxTranslationY(0);
- setFullscreenScale(1);
- if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
- params.width = ViewGroup.LayoutParams.MATCH_PARENT;
- params.height = ViewGroup.LayoutParams.MATCH_PARENT;
- setLayoutParams(params);
- }
+ fullscreenScale = 1f;
+ boxTranslationY = 0f;
+ expectedWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+ expectedHeight = ViewGroup.LayoutParams.MATCH_PARENT;
+ }
+
+ setFullscreenScale(fullscreenScale);
+ setBoxTranslationY(boxTranslationY);
+ if (params.width != expectedWidth || params.height != expectedHeight) {
+ params.width = expectedWidth;
+ params.height = expectedHeight;
+ setLayoutParams(params);
}
}
-
private float getFullscreenTrans(float endTranslation) {
float progress = ACCEL_DEACCEL.getInterpolation(mFullscreenProgress);
return Utilities.mapRange(progress, 0, endTranslation);
@@ -1293,6 +1314,13 @@
return this == getRecentsView().getRunningTaskView();
}
+ public boolean isFocusedTask() {
+ if (getRecentsView() == null) {
+ return false;
+ }
+ return this == getRecentsView().getFocusedTaskView();
+ }
+
public void setShowScreenshot(boolean showScreenshot) {
mShowScreenshot = showScreenshot;
}
@@ -1314,6 +1342,26 @@
rv.initiateSplitSelect(this, splitPositionOption);
}
+ private void setColorTint(float amount) {
+ mSnapshotView.setDimAlpha(amount);
+ mIconView.setIconColorTint(mTintingColor, amount);
+ mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount);
+ }
+
+ private float getColorTint() {
+ return mTintAmount;
+ }
+
+ /**
+ * Show the task view with a color tint (animates value).
+ */
+ public void showColorTint(boolean enable) {
+ ObjectAnimator tintAnimator = ObjectAnimator.ofFloat(
+ this, COLOR_TINT, enable ? MAX_PAGE_SCRIM_ALPHA : 0);
+ tintAnimator.setAutoCancel(true);
+ tintAnimator.start();
+ }
+
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index a412b39..4f27e21 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -16,7 +16,15 @@
package com.android.quickstep;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.quickstep.views.RecentsView;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
@@ -31,4 +39,49 @@
outerRule(new NavigationModeSwitchRule(mLauncher)).
around(super.getRulesInsideActivityMonitor());
}
+
+ @Override
+ protected void onLauncherActivityClose(Launcher launcher) {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ if (recentsView != null) {
+ recentsView.finishRecentsAnimation(true, null);
+ }
+ }
+
+ @Override
+ protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
+ boolean isResumed, boolean isStarted) {
+ if (!isInLiveTileMode(launcher, expectedContainerType)) {
+ super.checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
+ } else {
+ assertTrue("[Live Tile] hasBeenResumed() == isStarted(), hasBeenResumed(): "
+ + isResumed, isResumed != isStarted);
+ }
+ }
+
+ @Override
+ protected void checkLauncherStateInOverview(Launcher launcher,
+ ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
+ if (!isInLiveTileMode(launcher, expectedContainerType)) {
+ super.checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
+ isResumed);
+ } else {
+ assertTrue(
+ "[Live Tile] Launcher is not started or has been resumed in state: "
+ + expectedContainerType,
+ isStarted && !isResumed);
+ }
+ }
+
+ private boolean isInLiveTileMode(Launcher launcher,
+ LauncherInstrumentation.ContainerType expectedContainerType) {
+ if (!LIVE_TILE.get()
+ || expectedContainerType != LauncherInstrumentation.ContainerType.OVERVIEW) {
+ return false;
+ }
+
+ RecentsView recentsView = launcher.getOverviewPanel();
+ return recentsView.getSizeStrategy().isInLiveTileMode()
+ && recentsView.getRunningTaskId() != -1;
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 9732cdc..6e19436 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -100,6 +100,7 @@
// The test action.
mLauncher.getBackground().switchToOverview();
}
+ closeLauncherActivity();
mLauncher.pressHome();
}
}
diff --git a/res/color/overview_button.xml b/res/color/overview_button.xml
index 6ac36bf..aa48b78 100644
--- a/res/color/overview_button.xml
+++ b/res/color/overview_button.xml
@@ -2,10 +2,10 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:alpha="1"
- android:color="?attr/workspaceTextColor"
+ android:color="?android:attr/textColorPrimary"
android:state_enabled="true" />
<item
android:alpha="?android:disabledAlpha"
- android:color="?attr/workspaceTextColor"
+ android:color="?android:attr/textColorPrimary"
android:state_enabled="false" />
</selector>
\ No newline at end of file
diff --git a/res/layout/overview_actions_container.xml b/res/layout/overview_actions_container.xml
index 5946bf6..f152c7c 100644
--- a/res/layout/overview_actions_container.xml
+++ b/res/layout/overview_actions_container.xml
@@ -14,6 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+ loaded at runtime. -->
<Space
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index 09bdaaf..d50115b 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -1,3 +1,6 @@
<resources>
<bool name="allow_rotation">true</bool>
+
+ <!-- Hotseat -->
+ <bool name="hotseat_transpose_layout_with_orientation">false</bool>
</resources>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index ec07591..33fc553 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -3,7 +3,4 @@
<!-- All Apps & Widgets -->
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
<integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
-
-<!-- Hotseat -->
- <bool name="hotseat_transpose_layout_with_orientation">false</bool>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index c1c8f01..99f6c75 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -33,7 +33,6 @@
<attr name="workspaceKeyShadowColor" format="color" />
<attr name="workspaceStatusBarScrim" format="reference" />
<attr name="widgetsTheme" format="reference" />
- <attr name="loadingIconColor" format="color" />
<attr name="iconOnlyShortcutColor" format="color" />
<attr name="eduHalfSheetBGColor" format="color" />
@@ -44,7 +43,6 @@
<attr name="folderTextColor" format="color" />
<attr name="folderHintColor" format="color" />
<attr name="workProfileOverlayTextColor" format="color" />
- <attr name="disabledIconAlpha" format="float" />
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
@@ -134,6 +132,9 @@
<attr name="isScalable" format="boolean" />
<attr name="devicePaddingId" format="reference" />
+ <!-- whether the grid option is shown to the user -->
+ <attr name="visible" format="boolean" />
+
</declare-styleable>
<declare-styleable name="DevicePadding">
diff --git a/res/values/config.xml b/res/values/config.xml
index 65e2ab3..57f626c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -87,8 +87,6 @@
<!-- Default packages -->
<string name="wallpaper_picker_package" translatable="false"></string>
- <string name="calendar_component_name" translatable="false"></string>
- <string name="clock_component_name" translatable="false"></string>
<string name="local_colors_extraction_class" translatable="false"></string>
<!-- Accessibility actions -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1fccdf3..51dddab 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -84,6 +84,7 @@
<dimen name="fastscroll_end_margin">-26dp</dimen>
<!-- All Apps -->
+ <dimen name="all_apps_open_vertical_translate">96dp</dimen>
<dimen name="all_apps_search_bar_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
diff --git a/res/xml/size_limits_80x104.xml b/res/xml/size_limits_80x104.xml
index e11bc5e..f375549 100644
--- a/res/xml/size_limits_80x104.xml
+++ b/res/xml/size_limits_80x104.xml
@@ -36,11 +36,11 @@
launcher:a="0"
launcher:b="16dp"/>
<workspaceBottomPadding
- launcher:a="0.50"
+ launcher:a="0.56"
launcher:b="0"
launcher:c="16dp"/>
<hotseatBottomPadding
- launcher:a="0.50"
+ launcher:a="0.44"
launcher:b="0"
launcher:c="16dp"/>
</device-padding>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index c2bf1ae..36b6f01 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -18,64 +18,197 @@
import static android.os.Looper.getMainLooper;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.UserHandle;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
+import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowPackageManager;
+import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-import java.util.function.Consumer;
@RunWith(RobolectricTestRunner.class)
public class SimpleWidgetsSearchAlgorithmTest {
+ @Mock private IconCache mIconCache;
+
+ private InvariantDeviceProfile mTestProfile;
+ private WidgetsListHeaderEntry mCalendarHeaderEntry;
+ private WidgetsListContentEntry mCalendarContentEntry;
+ private WidgetsListHeaderEntry mCameraHeaderEntry;
+ private WidgetsListContentEntry mCameraContentEntry;
+ private WidgetsListHeaderEntry mClockHeaderEntry;
+ private WidgetsListContentEntry mClockContentEntry;
+ private Context mContext;
+
private SimpleWidgetsSearchAlgorithm mSimpleWidgetsSearchAlgorithm;
@Mock
- private WidgetsPickerSearchPipeline mSearchPipeline;
+ private PopupDataProvider mDataProvider;
@Mock
private SearchCallback<WidgetsListBaseEntry> mSearchCallback;
- @Captor
- private ArgumentCaptor<Consumer<List<WidgetsListBaseEntry>>> mConsumerCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mSearchPipeline);
+ doAnswer(invocation -> {
+ ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
+ return componentWithLabel.getComponent().getShortClassName();
+ }).when(mIconCache).getTitleNoCache(any());
+ mTestProfile = new InvariantDeviceProfile();
+ mTestProfile.numRows = 5;
+ mTestProfile.numColumns = 5;
+ mContext = RuntimeEnvironment.application;
+
+ mCalendarHeaderEntry =
+ createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
+ mCalendarContentEntry =
+ createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
+ mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
+ mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
+ mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
+ mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
+
+
+ mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mDataProvider);
+ doReturn(Collections.EMPTY_LIST).when(mDataProvider).getAllWidgets();
}
@Test
- public void doSearch_shouldQueryPipeline() {
- mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+ public void filter_shouldMatchOnAppName() {
+ doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+ mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+ .when(mDataProvider)
+ .getAllWidgets();
- verify(mSearchPipeline).query(eq("abc"), any());
+ assertEquals(List.of(
+ new WidgetsListSearchHeaderEntry(
+ mCalendarHeaderEntry.mPkgItem,
+ mCalendarHeaderEntry.mTitleSectionName,
+ mCalendarHeaderEntry.mWidgets),
+ mCalendarContentEntry,
+ new WidgetsListSearchHeaderEntry(
+ mCameraHeaderEntry.mPkgItem,
+ mCameraHeaderEntry.mTitleSectionName,
+ mCameraHeaderEntry.mWidgets),
+ mCameraContentEntry),
+ SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Ca"));
}
@Test
- public void doSearch_shouldInformSearchCallbackOnQueryResult() {
- ArrayList<WidgetsListBaseEntry> baseEntries = new ArrayList<>();
+ public void filter_shouldMatchOnWidgetLabel() {
+ doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+ mCameraContentEntry))
+ .when(mDataProvider)
+ .getAllWidgets();
- mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+ assertEquals(List.of(
+ new WidgetsListSearchHeaderEntry(
+ mCalendarHeaderEntry.mPkgItem,
+ mCalendarHeaderEntry.mTitleSectionName,
+ mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+ new WidgetsListContentEntry(
+ mCalendarHeaderEntry.mPkgItem,
+ mCalendarHeaderEntry.mTitleSectionName,
+ mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+ new WidgetsListSearchHeaderEntry(
+ mCameraHeaderEntry.mPkgItem,
+ mCameraHeaderEntry.mTitleSectionName,
+ mCameraHeaderEntry.mWidgets.subList(1, 3)),
+ new WidgetsListContentEntry(
+ mCameraHeaderEntry.mPkgItem,
+ mCameraHeaderEntry.mTitleSectionName,
+ mCameraHeaderEntry.mWidgets.subList(1, 3))),
+ SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Widget1"));
+ }
- verify(mSearchPipeline).query(eq("abc"), mConsumerCaptor.capture());
- mConsumerCaptor.getValue().accept(baseEntries);
+ @Test
+ public void doSearch_shouldInformCallback() {
+ doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+ mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+ .when(mDataProvider)
+ .getAllWidgets();
+ mSimpleWidgetsSearchAlgorithm.doSearch("Ca", mSearchCallback);
shadowOf(getMainLooper()).idle();
- // Verify SearchCallback#onSearchResult receives a query token along with the search
- // results. The query token is the original query string concatenated with the query
- // timestamp.
- verify(mSearchCallback).onSearchResult(matches("abc\t\\d*"), eq(baseEntries));
+ verify(mSearchCallback).onSearchResult(
+ matches("Ca"), argThat(a -> a != null && !a.isEmpty()));
+ }
+
+ private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
+ int numOfWidgets) {
+ List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+ PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+ widgetItems.get(0).user);
+
+ return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+ }
+
+ private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
+ int numOfWidgets) {
+ List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+ PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+ widgetItems.get(0).user);
+
+ return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+ }
+
+ private PackageItemInfo createPackageItemInfo(String packageName, String appName,
+ UserHandle userHandle) {
+ PackageItemInfo pInfo = new PackageItemInfo(packageName);
+ pInfo.title = appName;
+ pInfo.user = userHandle;
+ pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
+ return pInfo;
+ }
+
+ private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+ ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
+ ArrayList<WidgetItem> widgetItems = new ArrayList<>();
+ for (int i = 0; i < numOfWidgets; i++) {
+ ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
+ AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
+ widgetInfo.provider = cn;
+ ReflectionHelpers.setField(widgetInfo, "providerInfo",
+ packageManager.addReceiverIfNotPresent(cn));
+
+ WidgetItem widgetItem = new WidgetItem(
+ LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
+ mTestProfile, mIconCache);
+ widgetItems.add(widgetItem);
+ }
+ return widgetItems;
}
}
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
deleted file mode 100644
index 17ededd..0000000
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker.search;
-
-import static android.os.Looper.getMainLooper;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class SimpleWidgetsSearchPipelineTest {
- @Mock private IconCache mIconCache;
-
- private InvariantDeviceProfile mTestProfile;
- private WidgetsListHeaderEntry mCalendarHeaderEntry;
- private WidgetsListContentEntry mCalendarContentEntry;
- private WidgetsListHeaderEntry mCameraHeaderEntry;
- private WidgetsListContentEntry mCameraContentEntry;
- private WidgetsListHeaderEntry mClockHeaderEntry;
- private WidgetsListContentEntry mClockContentEntry;
- private Context mContext;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- doAnswer(invocation -> {
- ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
- return componentWithLabel.getComponent().getShortClassName();
- }).when(mIconCache).getTitleNoCache(any());
- mTestProfile = new InvariantDeviceProfile();
- mTestProfile.numRows = 5;
- mTestProfile.numColumns = 5;
- mContext = RuntimeEnvironment.application;
-
- mCalendarHeaderEntry =
- createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
- mCalendarContentEntry =
- createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
- mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
- mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
- mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
- mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
- }
-
- @Test
- public void query_shouldMatchOnAppName() {
- SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
- List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
- mCameraContentEntry, mClockHeaderEntry, mClockContentEntry));
-
- pipeline.query("Ca", results ->
- assertEquals(results,
- List.of(
- new WidgetsListSearchHeaderEntry(
- mCalendarHeaderEntry.mPkgItem,
- mCalendarHeaderEntry.mTitleSectionName,
- mCalendarHeaderEntry.mWidgets),
- mCalendarContentEntry,
- new WidgetsListSearchHeaderEntry(
- mCameraHeaderEntry.mPkgItem,
- mCameraHeaderEntry.mTitleSectionName,
- mCameraHeaderEntry.mWidgets),
- mCameraContentEntry)));
- shadowOf(getMainLooper()).idle();
- }
-
- @Test
- public void query_shouldMatchOnWidgetLabel() {
- SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
- List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
- mCameraContentEntry));
-
- pipeline.query("Widget1", results ->
- assertEquals(results,
- List.of(
- new WidgetsListSearchHeaderEntry(
- mCalendarHeaderEntry.mPkgItem,
- mCalendarHeaderEntry.mTitleSectionName,
- mCalendarHeaderEntry.mWidgets.subList(1, 2)),
- new WidgetsListContentEntry(
- mCalendarHeaderEntry.mPkgItem,
- mCalendarHeaderEntry.mTitleSectionName,
- mCalendarHeaderEntry.mWidgets.subList(1, 2)),
- new WidgetsListSearchHeaderEntry(
- mCameraHeaderEntry.mPkgItem,
- mCameraHeaderEntry.mTitleSectionName,
- mCameraHeaderEntry.mWidgets.subList(1, 3)),
- new WidgetsListContentEntry(
- mCameraHeaderEntry.mPkgItem,
- mCameraHeaderEntry.mTitleSectionName,
- mCameraHeaderEntry.mWidgets.subList(1, 3)))));
- shadowOf(getMainLooper()).idle();
- }
-
- private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
- int numOfWidgets) {
- List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
- PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
- widgetItems.get(0).user);
-
- return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
- }
-
- private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
- int numOfWidgets) {
- List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
- PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
- widgetItems.get(0).user);
-
- return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
- }
-
- private PackageItemInfo createPackageItemInfo(String packageName, String appName,
- UserHandle userHandle) {
- PackageItemInfo pInfo = new PackageItemInfo(packageName);
- pInfo.title = appName;
- pInfo.user = userHandle;
- pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
- return pInfo;
- }
-
- private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
- ArrayList<WidgetItem> widgetItems = new ArrayList<>();
- for (int i = 0; i < numOfWidgets; i++) {
- ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
- AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
- widgetInfo.provider = cn;
- ReflectionHelpers.setField(widgetInfo, "providerInfo",
- packageManager.addReceiverIfNotPresent(cn));
-
- WidgetItem widgetItem = new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache);
- widgetItems.add(widgetItem);
- }
- return widgetItems;
- }
-}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index e38ab74..5ba03ed 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -28,6 +28,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
import android.os.StrictMode;
@@ -329,6 +330,6 @@
* views
*/
public SearchAdapterProvider createSearchAdapterProvider(AllAppsContainerView allapps) {
- return new DefaultSearchAdapterProvider(this);
+ return new DefaultSearchAdapterProvider(this, allapps);
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2b58fb6..d333b49 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.graphics.IconShape.getShape;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
@@ -57,11 +56,12 @@
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.DotRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.PlaceHolderIconDrawable;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -92,12 +92,9 @@
private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
private static final float HIGHLIGHT_SCALE = 1.16f;
-
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
- private static final int ICON_UPDATE_ANIMATION_DURATION = 375;
-
private float mScaleForReorderBounce = 1f;
protected final Paint mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -335,7 +332,7 @@
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
- FastBitmapDrawable iconDrawable = newIcon(getContext(), info);
+ FastBitmapDrawable iconDrawable = info.newIcon(getContext());
mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
setIcon(iconDrawable);
@@ -933,7 +930,7 @@
private void resetIconScale() {
if (mIcon instanceof FastBitmapDrawable) {
- ((FastBitmapDrawable) mIcon).setScale(1f);
+ ((FastBitmapDrawable) mIcon).resetScale();
}
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 9df8d44..c16c44b 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -19,7 +19,6 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -213,7 +212,10 @@
mActivity = ActivityContext.lookupContext(context);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- mBorderSpacing = deviceProfile.cellLayoutBorderSpacingPx;
+ mBorderSpacing = mContainerType == FOLDER
+ ? deviceProfile.folderCellLayoutBorderSpacingPx
+ : deviceProfile.cellLayoutBorderSpacingPx;
+
mCellWidth = mCellHeight = -1;
mFixedCellWidth = mFixedCellHeight = -1;
@@ -602,7 +604,7 @@
if (child instanceof BubbleTextView) {
BubbleTextView bubbleChild = (BubbleTextView) child;
bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
- if (ENABLE_FOUR_COLUMNS.get()) {
+ if (mActivity.getDeviceProfile().isScalableGrid) {
bubbleChild.setCenterVertically(mContainerType != HOTSEAT);
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1ce5f4d..aea38a0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -123,6 +123,7 @@
public int folderIconOffsetYPx;
// Folder content
+ public int folderCellLayoutBorderSpacingPx;
public int folderContentPaddingLeftRight;
public int folderContentPaddingTop;
@@ -146,6 +147,7 @@
public final int hotseatBarSidePaddingEndPx;
// All apps
+ public int allAppsOpenVerticalTranslate;
public int allAppsCellHeightPx;
public int allAppsCellWidthPx;
public int allAppsIconSizePx;
@@ -247,6 +249,10 @@
: res.getDimensionPixelSize(R.dimen.dynamic_grid_left_right_margin);
desiredWorkspaceLeftRightOriginalPx = desiredWorkspaceLeftRightMarginPx;
+
+ allAppsOpenVerticalTranslate = res.getDimensionPixelSize(
+ R.dimen.all_apps_open_vertical_translate);
+
folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);
folderContentPaddingLeftRight =
res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right);
@@ -254,6 +260,7 @@
setCellLayoutBorderSpacing(pxFromDp(inv.borderSpacing, mInfo.metrics, 1f));
cellLayoutBorderSpacingOriginalPx = cellLayoutBorderSpacingPx;
+ folderCellLayoutBorderSpacingPx = cellLayoutBorderSpacingPx;
int cellLayoutPaddingLeftRightMultiplier = !isVerticalBarLayout() && isTablet
? PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER : 1;
@@ -352,13 +359,7 @@
}
private void setCellLayoutBorderSpacing(int borderSpacing) {
- if (isScalableGrid) {
- cellLayoutBorderSpacingPx = borderSpacing;
- folderContentPaddingLeftRight = borderSpacing;
- folderContentPaddingTop = borderSpacing;
- } else {
- cellLayoutBorderSpacingPx = 0;
- }
+ cellLayoutBorderSpacingPx = isScalableGrid ? borderSpacing : 0;
}
/**
@@ -404,12 +405,7 @@
.setMultiWindowMode(true)
.build();
- // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
- float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
- - iconDrawablePaddingPx - profile.iconTextSizePx;
- if (workspaceCellPaddingY < profile.iconDrawablePaddingPx * 2) {
- profile.adjustToHideWorkspaceLabels();
- }
+ profile.hideWorkspaceLabelsIfNotEnoughSpace();
// We use these scales to measure and layout the widgets using their full invariant profile
// sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
@@ -430,24 +426,32 @@
}
/**
- * Adjusts the profile so that the labels on the Workspace are hidden.
+ * Checks if there is enough space for labels on the workspace.
+ * If there is not, labels on the Workspace are hidden.
* It is important to call this method after the All Apps variables have been set.
*/
- private void adjustToHideWorkspaceLabels() {
- iconTextSizePx = 0;
- iconDrawablePaddingPx = 0;
- cellHeightPx = iconSizePx;
- autoResizeAllAppsCells();
+ private void hideWorkspaceLabelsIfNotEnoughSpace() {
+ float iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
+ float workspaceCellPaddingY = getCellSize().y - iconSizePx - iconDrawablePaddingPx
+ - iconTextHeight;
+
+ // We want enough space so that the text is closer to its corresponding icon.
+ if (workspaceCellPaddingY < iconTextHeight) {
+ iconTextSizePx = 0;
+ iconDrawablePaddingPx = 0;
+ cellHeightPx = iconSizePx;
+ autoResizeAllAppsCells();
+ }
}
/**
* Re-computes the all-apps cell size to be independent of workspace
*/
public void autoResizeAllAppsCells() {
- int topBottomPadding = allAppsIconDrawablePaddingPx * (isVerticalBarLayout() ? 2 : 1);
+ int textHeight = Utilities.calculateTextHeight(allAppsIconTextSizePx);
+ int topBottomPadding = textHeight;
allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx
- + Utilities.calculateTextHeight(allAppsIconTextSizePx)
- + topBottomPadding * 2;
+ + textHeight + (topBottomPadding * 2);
}
/**
@@ -536,9 +540,7 @@
allAppsIconSizePx = pxFromDp(inv.allAppsIconSize, mInfo.metrics);
allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, mInfo.metrics);
allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
- // We use 4 below to ensure labels are closer to their corresponding icon.
- allAppsCellHeightPx = Math.round(allAppsIconSizePx + allAppsIconTextSizePx
- + (4 * allAppsIconDrawablePaddingPx));
+ autoResizeAllAppsCells();
} else {
allAppsIconSizePx = iconSizePx;
allAppsIconTextSizePx = iconTextSizePx;
@@ -547,9 +549,8 @@
}
allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
- if (isVerticalBarLayout()) {
- // Always hide the Workspace text with vertical bar layout.
- adjustToHideWorkspaceLabels();
+ if (isVerticalLayout) {
+ hideWorkspaceLabelsIfNotEnoughSpace();
}
// Hotseat
@@ -587,14 +588,14 @@
// Check if the icons fit within the available height.
float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
- + ((inv.numFolderRows - 1) * cellLayoutBorderSpacingPx);
+ + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacingPx);
int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderBottomPanelSize
- folderMargin - folderContentPaddingTop;
float scaleY = contentMaxHeight / contentUsedHeight;
// Check if the icons fit within the available width.
float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
- + ((inv.numFolderColumns - 1) * cellLayoutBorderSpacingPx);
+ + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacingPx);
int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin
- folderContentPaddingLeftRight * 2;
float scaleX = contentMaxWidth / contentUsedWidth;
@@ -612,11 +613,25 @@
folderLabelTextSizePx = (int) (folderChildTextSizePx * folderLabelTextScale);
int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
- int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale);
- int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding) * scale);
- folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX;
- folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight;
+ if (isScalableGrid) {
+ folderCellWidthPx = (int) (cellWidthPx * scale);
+ folderCellHeightPx = (int) (cellHeightPx * scale);
+
+ int borderSpacing = (int) (cellLayoutBorderSpacingOriginalPx * scale);
+ folderCellLayoutBorderSpacingPx = borderSpacing;
+ folderContentPaddingLeftRight = borderSpacing;
+ folderContentPaddingTop = borderSpacing;
+ } else {
+ int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
+ * scale);
+ int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding)
+ * scale);
+
+ folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX;
+ folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight;
+ }
+
folderChildDrawablePaddingPx = Math.max(0,
(folderCellHeightPx - folderChildIconSizePx - textHeight) / 3);
}
@@ -868,6 +883,8 @@
writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
folderChildDrawablePaddingPx));
+ writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacingPx",
+ folderCellLayoutBorderSpacingPx));
writer.println(prefix + pxToDpStr("cellLayoutBorderSpacingPx",
cellLayoutBorderSpacingPx));
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
deleted file mode 100644
index 0027a50..0000000
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
-
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.Property;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.util.Themes;
-
-
-public class FastBitmapDrawable extends Drawable {
-
- private static final float PRESSED_SCALE = 1.1f;
-
- private static final float DISABLED_DESATURATION = 1f;
- private static final float DISABLED_BRIGHTNESS = 0.5f;
-
- public static final int CLICK_FEEDBACK_DURATION = 200;
-
- private static ColorFilter sDisabledFColorFilter;
-
- protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
- protected Bitmap mBitmap;
- protected final int mIconColor;
-
- @Nullable private ColorFilter mColorFilter;
-
- private boolean mIsPressed;
- private boolean mIsDisabled;
- private float mDisabledAlpha = 1f;
- private float mRoundedCornersRadius = 0f;
- private final Path mClipPath = new Path();
-
- // Animator and properties for the fast bitmap drawable's scale
- private static final Property<FastBitmapDrawable, Float> SCALE
- = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
- @Override
- public Float get(FastBitmapDrawable fastBitmapDrawable) {
- return fastBitmapDrawable.mScale;
- }
-
- @Override
- public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
- fastBitmapDrawable.mScale = value;
- fastBitmapDrawable.invalidateSelf();
- }
- };
- private ObjectAnimator mScaleAnimation;
- private float mScale = 1;
-
- private int mAlpha = 255;
-
- public FastBitmapDrawable(Bitmap b) {
- this(b, Color.TRANSPARENT);
- }
-
- public FastBitmapDrawable(BitmapInfo info) {
- this(info.icon, info.color);
- }
-
- protected FastBitmapDrawable(Bitmap b, int iconColor) {
- this(b, iconColor, false);
- }
-
- protected FastBitmapDrawable(Bitmap b, int iconColor, boolean isDisabled) {
- mBitmap = b;
- mIconColor = iconColor;
- setFilterBitmap(true);
- setIsDisabled(isDisabled);
- }
-
- @Override
- public final void draw(Canvas canvas) {
- if (mRoundedCornersRadius > 0) {
- float radius = mRoundedCornersRadius * mScale;
- mClipPath.reset();
- mClipPath.addRoundRect(0, 0, getIntrinsicWidth(), getIntrinsicHeight(),
- radius, radius, Path.Direction.CCW);
- canvas.clipPath(mClipPath);
- }
- if (mScale != 1f) {
- int count = canvas.save();
- Rect bounds = getBounds();
- canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
- drawInternal(canvas, bounds);
- canvas.restoreToCount(count);
- } else {
- drawInternal(canvas, getBounds());
- }
- }
-
- protected void drawInternal(Canvas canvas, Rect bounds) {
- canvas.drawBitmap(mBitmap, null, bounds, mPaint);
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- mColorFilter = cf;
- updateFilter();
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- if (mAlpha != alpha) {
- mAlpha = alpha;
- mPaint.setAlpha(alpha);
- invalidateSelf();
- }
- }
-
- @Override
- public void setFilterBitmap(boolean filterBitmap) {
- mPaint.setFilterBitmap(filterBitmap);
- mPaint.setAntiAlias(filterBitmap);
- }
-
- public int getAlpha() {
- return mAlpha;
- }
-
- public void setScale(float scale) {
- if (mScaleAnimation != null) {
- mScaleAnimation.cancel();
- mScaleAnimation = null;
- }
- mScale = scale;
- invalidateSelf();
- }
-
- public float getAnimatedScale() {
- return mScaleAnimation == null ? 1 : mScale;
- }
-
- public float getScale() {
- return mScale;
- }
-
- public void setRoundedCornersRadius(float radius) {
- mRoundedCornersRadius = radius;
- }
-
- public float getRoundedCornersRadius() {
- return mRoundedCornersRadius;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mBitmap.getWidth();
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mBitmap.getHeight();
- }
-
- @Override
- public int getMinimumWidth() {
- return getBounds().width();
- }
-
- @Override
- public int getMinimumHeight() {
- return getBounds().height();
- }
-
- @Override
- public boolean isStateful() {
- return true;
- }
-
- @Override
- public ColorFilter getColorFilter() {
- return mPaint.getColorFilter();
- }
-
- @Override
- protected boolean onStateChange(int[] state) {
- boolean isPressed = false;
- for (int s : state) {
- if (s == android.R.attr.state_pressed) {
- isPressed = true;
- break;
- }
- }
- if (mIsPressed != isPressed) {
- mIsPressed = isPressed;
-
- if (mScaleAnimation != null) {
- mScaleAnimation.cancel();
- mScaleAnimation = null;
- }
-
- if (mIsPressed) {
- // Animate when going to pressed state
- mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, PRESSED_SCALE);
- mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
- mScaleAnimation.setInterpolator(ACCEL);
- mScaleAnimation.start();
- } else {
- if (isVisible()) {
- mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, 1f);
- mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
- mScaleAnimation.setInterpolator(DEACCEL);
- mScaleAnimation.start();
- } else {
- mScale = 1f;
- invalidateSelf();
- }
- }
- return true;
- }
- return false;
- }
-
- public void setIsDisabled(boolean isDisabled) {
- if (mIsDisabled != isDisabled) {
- mIsDisabled = isDisabled;
- updateFilter();
- }
- }
-
- protected boolean isDisabled() {
- return mIsDisabled;
- }
-
- private ColorFilter getDisabledColorFilter() {
- if (sDisabledFColorFilter == null) {
- ColorMatrix tempBrightnessMatrix = new ColorMatrix();
- ColorMatrix tempFilterMatrix = new ColorMatrix();
-
- tempFilterMatrix.setSaturation(1f - DISABLED_DESATURATION);
- float scale = 1 - DISABLED_BRIGHTNESS;
- int brightnessI = (int) (255 * DISABLED_BRIGHTNESS);
- float[] mat = tempBrightnessMatrix.getArray();
- mat[0] = scale;
- mat[6] = scale;
- mat[12] = scale;
- mat[4] = brightnessI;
- mat[9] = brightnessI;
- mat[14] = brightnessI;
- mat[18] = mDisabledAlpha;
- tempFilterMatrix.preConcat(tempBrightnessMatrix);
- sDisabledFColorFilter = new ColorMatrixColorFilter(tempFilterMatrix);
- }
- return sDisabledFColorFilter;
- }
-
- /**
- * Updates the paint to reflect the current brightness and saturation.
- */
- protected void updateFilter() {
- mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter);
- invalidateSelf();
- }
-
- @Override
- public ConstantState getConstantState() {
- return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
- }
-
- protected static class FastBitmapConstantState extends ConstantState {
- protected final Bitmap mBitmap;
- protected final int mIconColor;
- protected final boolean mIsDisabled;
-
- public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
- mBitmap = bitmap;
- mIconColor = color;
- mIsDisabled = isDisabled;
- }
-
- @Override
- public FastBitmapDrawable newDrawable() {
- return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
- }
-
- @Override
- public int getChangingConfigurations() {
- return 0;
- }
- }
-
- /**
- * Interface to be implemented by custom {@link BitmapInfo} to handle drawable construction
- */
- public interface Factory {
-
- /**
- * Called to create a new drawable
- */
- FastBitmapDrawable newDrawable();
- }
-
- /**
- * Returns a FastBitmapDrawable with the icon.
- */
- public static FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
- FastBitmapDrawable drawable = newIcon(context, info.bitmap);
- drawable.setIsDisabled(info.isDisabled());
- return drawable;
- }
-
- /**
- * Creates a drawable for the provided BitmapInfo
- */
- public static FastBitmapDrawable newIcon(Context context, BitmapInfo info) {
- final FastBitmapDrawable drawable;
- if (info instanceof Factory) {
- drawable = ((Factory) info).newDrawable();
- } else if (info.isLowRes()) {
- drawable = new PlaceHolderIconDrawable(info, context);
- } else {
- drawable = new FastBitmapDrawable(info);
- }
- drawable.mDisabledAlpha = Themes.getFloat(context, R.attr.disabledIconAlpha, 1f);
- return drawable;
- }
-}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 4049ed6..5429806 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -96,7 +96,6 @@
} else {
setGridSize(idp.numHotseatIcons, 1);
}
- showInlineQsb();
}
@Override
@@ -181,10 +180,6 @@
mOnVisibilityAggregatedCallback = callback;
}
- protected void showInlineQsb() {
- //Does nothing
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -223,13 +218,6 @@
}
/**
- * Returns the first View for which the given itemOperator returns true, or null.
- */
- public View getFirstItemMatch(Workspace.ItemOperator itemOperator) {
- return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator);
- }
-
- /**
* Sets the alpha value of just our ShortcutAndWidgetContainer.
*/
public void setIconsAlpha(float alpha) {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index b0c3bb4..754e988 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -626,6 +626,8 @@
private final boolean isScalable;
private final int devicePaddingId;
+ public final boolean visible;
+
private final SparseArray<TypedValue> extraAttrs;
public GridOption(Context context, AttributeSet attrs) {
@@ -652,6 +654,8 @@
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, 0);
+ visible = a.getBoolean(R.styleable.GridDisplayOption_visible, true);
+
a.recycle();
extraAttrs = Themes.createValueMap(context, attrs,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 89c0f66..df5f953 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -34,7 +34,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.LauncherState.NO_SCALE;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
@@ -61,6 +60,10 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.ActivityNotFoundException;
@@ -149,7 +152,6 @@
import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
-import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging;
@@ -269,9 +271,6 @@
private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@Thunk @VisibleForTesting public static final int NEW_APPS_ANIMATION_DELAY = 500;
- private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1;
- private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0;
-
private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
private Configuration mOldConfig;
@@ -342,8 +341,6 @@
private RotationHelper mRotationHelper;
- private float mCurrentAssistantVisibility = 0f;
-
protected LauncherOverlayManager mOverlayManager;
// If true, overlay callbacks are deferred
private boolean mDeferOverlayCallbacks;
@@ -380,6 +377,44 @@
.build());
}
+ if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.NOTIFY_CRASHES.get()) {
+ final String notificationChannelId = "com.android.launcher3.Debug";
+ final String notificationChannelName = "Debug";
+ final String notificationTag = "Debug";
+ final int notificationId = 0;
+
+ NotificationManager notificationManager = getSystemService(NotificationManager.class);
+ notificationManager.createNotificationChannel(new NotificationChannel(
+ notificationChannelId, notificationChannelName,
+ NotificationManager.IMPORTANCE_HIGH));
+
+ Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
+ String stackTrace = Log.getStackTraceString(throwable);
+
+ Intent shareIntent = new Intent(Intent.ACTION_SEND);
+ shareIntent.setType("text/plain");
+ shareIntent.putExtra(Intent.EXTRA_TEXT, stackTrace);
+ shareIntent = Intent.createChooser(shareIntent, null);
+ PendingIntent sharePendingIntent = PendingIntent.getActivity(
+ this, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT
+ );
+
+ Notification notification = new Notification.Builder(this, notificationChannelId)
+ .setSmallIcon(android.R.drawable.ic_menu_close_clear_cancel)
+ .setContentTitle("Launcher crash detected!")
+ .setStyle(new Notification.BigTextStyle().bigText(stackTrace))
+ .addAction(android.R.drawable.ic_menu_share, "Share", sharePendingIntent)
+ .build();
+ notificationManager.notify(notificationTag, notificationId, notification);
+
+ Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler =
+ Thread.getDefaultUncaughtExceptionHandler();
+ if (defaultUncaughtExceptionHandler != null) {
+ defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
+ }
+ });
+ }
+
super.onCreate(savedInstanceState);
LauncherAppState app = LauncherAppState.getInstance(this);
@@ -457,24 +492,6 @@
OverlayPlugin.class, false /* allowedMultiple */);
mRotationHelper.initialize();
-
- mStateManager.addStateListener(new StateListener<LauncherState>() {
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- float alpha = 1f - mCurrentAssistantVisibility;
- if (finalState == NORMAL) {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
- } else if (finalState == OVERVIEW) {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
- mScrimView.setAlpha(alpha);
- } else {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(1f);
- mScrimView.setAlpha(1f);
- }
- }
- });
-
TraceHelper.INSTANCE.endSection(traceToken);
mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
@@ -563,15 +580,7 @@
}
public void onAssistantVisibilityChanged(float visibility) {
- mCurrentAssistantVisibility = visibility;
- float alpha = 1f - visibility;
- LauncherState state = mStateManager.getState();
- if (state == NORMAL) {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
- } else if (state == OVERVIEW) {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
- mScrimView.setAlpha(alpha);
- }
+ mHotseat.getQsb().setAlpha(1f - visibility);
}
private void initDeviceProfile(InvariantDeviceProfile idp) {
@@ -1027,7 +1036,19 @@
}
// When multiple pages are visible, show persistent page indicator
mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE));
+
mPrevLauncherState = mStateManager.getCurrentStableState();
+ if (mPrevLauncherState != state && ALL_APPS.equals(state)
+ // Making sure mAllAppsSessionLogId is null to avoid double logging.
+ && mAllAppsSessionLogId == null) {
+ // creates new instance ID since new all apps session is started.
+ mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
+ getStatsLogManager()
+ .logger()
+ .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+ ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
+ : LAUNCHER_ALLAPPS_ENTRY);
+ }
}
@Override
@@ -1052,16 +1073,8 @@
getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
}
- if (ALL_APPS.equals(state)) {
- // creates new instance ID since new all apps session is started.
- mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
- getStatsLogManager()
- .logger()
- .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
- ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
- : LAUNCHER_ALLAPPS_ENTRY);
- } else if (ALL_APPS.equals(mPrevLauncherState)
- // Check if mLogInstanceId is not null to make sure exit event is logged only once.
+ if (mPrevLauncherState != state && !ALL_APPS.equals(state)
+ // Making sure mAllAppsSessionLogId is not null to avoid double logging.
&& mAllAppsSessionLogId != null) {
getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_EXIT);
mAllAppsSessionLogId = null;
@@ -1781,9 +1794,7 @@
@Override
public Rect getFolderBoundingBox() {
// We need to bound the folder to the currently visible workspace area
- Rect folderBoundingBox = new Rect();
- getWorkspace().getPageAreaRelativeToDragLayer(folderBoundingBox);
- return folderBoundingBox;
+ return getWorkspace().getPageAreaRelativeToDragLayer();
}
@Override
@@ -2763,6 +2774,13 @@
return new float[] {NO_SCALE, NO_OFFSET};
}
+ /**
+ * @see LauncherState#getTaskbarScale(Launcher)
+ */
+ public float getNormalTaskbarScale() {
+ return 1f;
+ }
+
public static Launcher getLauncher(Context context) {
return fromContext(context);
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 57d7600..4754558 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -17,8 +17,11 @@
package com.android.launcher3;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import android.content.ComponentName;
import android.content.Context;
@@ -37,10 +40,10 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.InstallSessionTracker;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.widget.custom.CustomWidgetManager;
@@ -113,7 +116,7 @@
mNotificationSettingsChangedListener = this::onNotificationSettingsChanged;
mSettingsCache.register(NOTIFICATION_BADGING_URI,
mNotificationSettingsChangedListener);
- mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+ onNotificationSettingsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
}
public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
@@ -122,6 +125,34 @@
mContext = context;
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
+
+ // b/175329686 Temporary logic to gracefully migrate group of users to the new 4x5 grid.
+ String gridName = InvariantDeviceProfile.getCurrentGridName(context);
+ if (ENABLE_FOUR_COLUMNS.get()
+ || "reasonable".equals(gridName)
+ || ENABLE_FOUR_COLUMNS.key.equals(gridName)) {
+ // Reset flag and remove it from developer options to prevent it from being enabled
+ // again.
+ ENABLE_FOUR_COLUMNS.reset(context);
+ FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS);
+
+ // Force migration code to run
+ Utilities.getPrefs(context).edit()
+ .remove(KEY_MIGRATION_SRC_HOTSEAT_COUNT)
+ .remove(KEY_MIGRATION_SRC_WORKSPACE_SIZE)
+ .apply();
+
+ // We make an empty call here to ensure the database is created with the old IDP grid,
+ // so that when we set the new grid the migration can proceeds as expected.
+ LauncherSettings.Settings.call(context.getContentResolver(), "");
+
+ String newGridName = "practical";
+ Utilities.getPrefs(mContext).edit().putString("idp_grid_name", newGridName).commit();
+ mInvariantDeviceProfile.setCurrentGrid(context, "practical");
+ } else {
+ FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS);
+ }
+
mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext));
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index 25afb55..6c0daa4 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -15,6 +15,7 @@
private static final String XML = ".xml";
public static final String LAUNCHER_DB = "launcher.db";
+ public static final String LAUNCHER_4_BY_5_DB = "launcher_4_by_5.db";
public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db";
public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db";
public static final String LAUNCHER_2_BY_2_DB = "launcher_2_by_2.db";
@@ -30,6 +31,7 @@
public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
LAUNCHER_DB,
+ LAUNCHER_4_BY_5_DB,
LAUNCHER_4_BY_4_DB,
LAUNCHER_3_BY_3_DB,
LAUNCHER_2_BY_2_DB,
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 06bc438..1003958 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -17,9 +17,11 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_MODAL_TASK_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL;
@@ -89,7 +91,7 @@
}
};
- private static final LauncherState[] sAllStates = new LauncherState[9];
+ private static final LauncherState[] sAllStates = new LauncherState[10];
/**
* TODO: Create a separate class for NORMAL state.
@@ -112,6 +114,8 @@
SPRING_LOADED_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(
+ HINT_STATE_TWO_BUTTON_ORDINAL, LAUNCHER_STATE_OVERVIEW);
public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
public static final LauncherState OVERVIEW_MODAL_TASK = OverviewState.newModalTaskState(
@@ -176,6 +180,10 @@
return launcher.getNormalOverviewScaleAndOffset();
}
+ public float getTaskbarScale(Launcher launcher) {
+ return launcher.getNormalTaskbarScale();
+ }
+
public float getOverviewFullscreenProgress() {
return 0;
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 76885cc..01f7c71 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -715,13 +715,10 @@
final int primaryDimension = bounds.primaryDimension;
final int childPrimaryEnd = bounds.childPrimaryEnd;
- // In case the pages are of different width, align the page to left or right edge
- // based on the orientation.
- // In case we have multiple panels on the screen, scrollOffsetEnd is the scroll
- // needed for the whole visible area, so we have to divide it by panelCount.
- final int pageScroll = mIsRtl
- ? (childStart - scrollOffsetStart)
- : Math.max(0, childPrimaryEnd - scrollOffsetEnd / getPanelCount());
+ // In case the pages are of different width, align the page to left edge for non-RTL
+ // or right edge for RTL.
+ final int pageScroll =
+ mIsRtl ? childPrimaryEnd - scrollOffsetEnd : childStart - scrollOffsetStart;
if (outPageScrolls[i] != pageScroll) {
pageScrollChanged = true;
outPageScrolls[i] = pageScroll;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e57844d..1776777 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -37,6 +37,8 @@
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
@@ -64,11 +66,13 @@
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
+import androidx.core.graphics.ColorUtils;
import androidx.core.os.BuildCompat;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.GridCustomizationsProvider;
import com.android.launcher3.graphics.TintedDrawableSpan;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.ShortcutCachingLogic;
@@ -731,6 +735,23 @@
}
}
+ /**
+ * Make a color filter that blends a color into the destination based on a scalable amout.
+ *
+ * @param color to blend in.
+ * @param tintAmount [0-1] 0 no tinting, 1 full color.
+ * @return ColorFilter for tinting, or {@code null} if no filter is needed.
+ */
+ public static ColorFilter makeColorTintingColorFilter(int color, float tintAmount) {
+ if (tintAmount == 0f) {
+ return null;
+ }
+ return new LightingColorFilter(
+ // This isn't blending in white, its making a multiplication mask for the base color
+ ColorUtils.blendARGB(Color.WHITE, 0, tintAmount),
+ ColorUtils.blendARGB(0, color, tintAmount));
+ }
+
private static class FixedSizeEmptyDrawable extends ColorDrawable {
private final int mSize;
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 446c873..f43452c 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -37,6 +37,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
@@ -540,20 +541,17 @@
c.setBitmap(preview);
c.drawColor(0, PorterDuff.Mode.CLEAR);
}
- RectF boxRect = drawBoxWithShadow(c, size, size);
+
+ drawBoxWithShadow(c, size, size);
LauncherIcons li = LauncherIcons.obtain(mContext);
- Bitmap icon = li.createBadgedIconBitmap(
+ Drawable icon = li.createBadgedIconBitmap(
mutateOnMainThread(info.getFullResIcon(mIconCache)),
- Process.myUserHandle(), 0).icon;
+ Process.myUserHandle(), 0).newIcon(launcher);
li.recycle();
- Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
-
- boxRect.set(0, 0, iconSize, iconSize);
- boxRect.offset(padding, padding);
- c.drawBitmap(icon, src, boxRect,
- new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
+ icon.setBounds(padding, padding, padding + iconSize, padding + iconSize);
+ icon.draw(c);
c.setBitmap(null);
return preview;
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6a16da9..981cf89 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -83,6 +83,7 @@
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.graphics.WorkspaceDragScrim;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
@@ -1999,16 +2000,26 @@
}
/**
- * Computes the area relative to dragLayer which is used to display a page.
+ * Computes and returns the area relative to dragLayer which is used to display a page.
+ * In case we have multiple pages displayed at the same time, we return the union of the areas.
*/
- public void getPageAreaRelativeToDragLayer(Rect outArea) {
- CellLayout child = (CellLayout) getChildAt(getNextPage());
- if (child == null) {
- return;
+ public Rect getPageAreaRelativeToDragLayer() {
+ Rect area = new Rect();
+ int nextPage = getNextPage();
+ int panelCount = getPanelCount();
+ for (int page = nextPage; page < nextPage + panelCount; page++) {
+ CellLayout child = (CellLayout) getChildAt(page);
+ if (child == null) {
+ break;
+ }
+
+ ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
+ Rect tmpRect = new Rect();
+ mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, tmpRect);
+ area.union(tmpRect);
}
- ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
- mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, outArea);
+ return area;
}
@Override
@@ -2967,8 +2978,10 @@
* @param user The user of the app to match.
*/
public View getFirstMatchForAppClose(String packageName, UserHandle user) {
- final int curPage = getCurrentPage();
- final CellLayout currentPage = (CellLayout) getPageAt(curPage);
+ List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
+ cellLayouts.add(getHotseat());
+ getVisiblePages().forEach(page -> cellLayouts.add((CellLayout) page));
+
final Workspace.ItemOperator packageAndUser = (ItemInfo info, View view) -> info != null
&& info.getTargetComponent() != null
&& TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
@@ -2989,13 +3002,11 @@
// Order: App icons, app in folder. Items in hotseat get returned first.
if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
- return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
- packageAndUserAndApp, packageAndUserAndAppInFolder);
+ return getFirstMatch(cellLayouts, packageAndUserAndApp, packageAndUserAndAppInFolder);
} else {
// Do not use Folder as a criteria, since it'll cause a crash when trying to draw
// FolderAdaptiveIcon as the background.
- return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
- packageAndUserAndApp);
+ return getFirstMatch(cellLayouts, packageAndUserAndApp);
}
}
@@ -3029,7 +3040,7 @@
* @param operators List of operators, in order starting from best matching operator.
* @return
*/
- View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
+ View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
// This array is filled with the first match for each operator.
final View[] matches = new View[operators.length];
// For efficiency, the outer loop should be CellLayout.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 16e022c..e0a4d4a 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -105,47 +105,39 @@
int elements = state.getVisibleElements(mLauncher);
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
- boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
Hotseat hotseat = mWorkspace.getHotseat();
- if (playAtomicComponent) {
- Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
- LauncherState fromState = mLauncher.getStateManager().getState();
- boolean shouldSpring = propertySetter instanceof PendingAnimation
- && fromState == HINT_STATE && state == NORMAL;
- if (shouldSpring) {
- ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
- mWorkspace, mNewScale));
- } else {
- propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
- }
+ Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
+ LauncherState fromState = mLauncher.getStateManager().getState();
- setPivotToScaleWithWorkspace(hotseat);
- float hotseatScale = hotseatScaleAndTranslation.scale;
- if (shouldSpring) {
- PendingAnimation pa = (PendingAnimation) propertySetter;
- pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
- } else {
- Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
- scaleInterpolator);
- propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
- hotseatScaleInterpolator);
- }
-
- float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
- float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
- propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
- workspacePageIndicatorAlpha, fadeInterpolator);
+ boolean shouldSpring = propertySetter instanceof PendingAnimation
+ && fromState == HINT_STATE && state == NORMAL;
+ if (shouldSpring) {
+ ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
+ mWorkspace, mNewScale));
+ } else {
+ propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
}
- if (config.onlyPlayAtomicComponent()) {
- // Only the alpha and scale, handled above, are included in the atomic animation.
- return;
+ setPivotToScaleWithWorkspace(hotseat);
+ float hotseatScale = hotseatScaleAndTranslation.scale;
+ if (shouldSpring) {
+ PendingAnimation pa = (PendingAnimation) propertySetter;
+ pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
+ } else {
+ Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
+ scaleInterpolator);
+ propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
+ hotseatScaleInterpolator);
}
- Interpolator translationInterpolator = !playAtomicComponent
- ? LINEAR
- : config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
+ float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
+ propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
+ float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
+ propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
+ workspacePageIndicatorAlpha, fadeInterpolator);
+
+ Interpolator translationInterpolator =
+ config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X,
scaleAndTranslation.translationX, translationInterpolator);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
@@ -195,17 +187,12 @@
int drawableAlpha = state.hasFlag(FLAG_WORKSPACE_HAS_BACKGROUNDS)
? Math.round(pageAlpha * 255) : 0;
- if (!config.onlyPlayAtomicComponent()) {
- // Don't update the scrim during the atomic animation.
- propertySetter.setInt(cl.getScrimBackground(),
- DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
- }
- if (config.playAtomicOverviewScaleComponent()) {
- Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
- pageAlphaProvider.interpolator);
- propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
- pageAlpha, fadeInterpolator);
- }
+ propertySetter.setInt(cl.getScrimBackground(),
+ DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
+ Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
+ pageAlphaProvider.interpolator);
+ propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
+ pageAlpha, fadeInterpolator);
}
/**
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index db7fd3f..a5852ba 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -265,7 +265,7 @@
List<OptionItem> actions = getSupportedResizeActions(host, info);
Rect pos = new Rect();
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
- ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions);
+ ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions, false);
popup.requestFocus();
popup.setOnCloseCallback(host::requestFocus);
return true;
@@ -294,15 +294,17 @@
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
- actions.add(new OptionItem(
- R.string.action_increase_width, R.drawable.ic_widget_width_increase,
+ actions.add(new OptionItem(mLauncher,
+ R.string.action_increase_width,
+ R.drawable.ic_widget_width_increase,
IGNORE,
v -> performResizeAction(R.string.action_increase_width, host, info)));
}
if (info.spanX > info.minSpanX && info.spanX > 1) {
- actions.add(new OptionItem(
- R.string.action_decrease_width, R.drawable.ic_widget_width_decrease,
+ actions.add(new OptionItem(mLauncher,
+ R.string.action_decrease_width,
+ R.drawable.ic_widget_width_decrease,
IGNORE,
v -> performResizeAction(R.string.action_decrease_width, host, info)));
}
@@ -311,15 +313,17 @@
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) ||
layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) {
- actions.add(new OptionItem(
- R.string.action_increase_height, R.drawable.ic_widget_height_increase,
+ actions.add(new OptionItem(mLauncher,
+ R.string.action_increase_height,
+ R.drawable.ic_widget_height_increase,
IGNORE,
v -> performResizeAction(R.string.action_increase_height, host, info)));
}
if (info.spanY > info.minSpanY && info.spanY > 1) {
- actions.add(new OptionItem(
- R.string.action_decrease_height, R.drawable.ic_widget_height_decrease,
+ actions.add(new OptionItem(mLauncher,
+ R.string.action_decrease_height,
+ R.drawable.ic_widget_height_decrease,
IGNORE,
v -> performResizeAction(R.string.action_decrease_height, host, info)));
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index bf0a88f..406e785 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -64,8 +64,6 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
@@ -77,10 +75,9 @@
public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener {
- private static final float FLING_VELOCITY_MULTIPLIER = 135f;
+ private static final float FLING_VELOCITY_MULTIPLIER = 1000 * .8f;
// Starts the springs after at least 55% of the animation has passed.
private static final float FLING_ANIMATION_THRESHOLD = 0.55f;
- private static final int ALPHA_CHANNEL_COUNT = 2;
protected final BaseDraggingActivity mLauncher;
protected final AdapterHolder[] mAH;
@@ -107,8 +104,6 @@
protected RecyclerViewFastScroller mTouchHandler;
protected final Point mFastScrollerOffset = new Point();
- private final MultiValueAlpha mMultiValueAlpha;
-
private Rect mInsets = new Rect();
SearchAdapterProvider mSearchAdapterProvider;
@@ -139,13 +134,6 @@
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
-
- addSpringView(R.id.all_apps_header);
- addSpringView(R.id.apps_list_view);
- addSpringView(R.id.all_apps_tabs_view_pager);
-
- mMultiValueAlpha = new MultiValueAlpha(this, ALPHA_CHANNEL_COUNT);
-
}
/**
@@ -161,25 +149,14 @@
return mAllAppsStore;
}
- public AlphaProperty getAlphaProperty(int index) {
- return mMultiValueAlpha.getProperty(index);
- }
-
public WorkModeSwitch getWorkModeSwitch() {
return mWorkModeSwitch;
}
-
- @Override
- protected void setDampedScrollShift(float shift) {
- // Bound the shift amount to avoid content from drawing on top (Y-val) of the QSB.
- float maxShift = getSearchView().getHeight() / 2f;
- super.setDampedScrollShift(Utilities.boundToRange(shift, -maxShift, maxShift));
- }
-
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
for (AdapterHolder holder : mAH) {
+ holder.adapter.setAppsPerRow(dp.inv.numAllAppsColumns);
if (holder.recyclerView != null) {
// Remove all views and clear the pool, while keeping the data same. After this
// call, all the viewHolders will be recreated.
@@ -407,12 +384,6 @@
}
}
- @Override
- public int getCanvasClipTopForOverscroll() {
- // Do not clip if the QSB is attached to the spring, otherwise the QSB will get clipped.
- return mSpringViews.get(getSearchView().getId()) ? 0 : mHeader.getTop();
- }
-
private void rebindAdapters(boolean showTabs) {
rebindAdapters(showTabs, false /* force */);
}
@@ -639,11 +610,8 @@
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (shouldSpring
&& valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
- int searchViewId = getSearchView().getId();
- addSpringView(searchViewId);
- finishWithShiftAndVelocity(1, velocity * FLING_VELOCITY_MULTIPLIER,
- (anim, canceled, value, velocity) -> removeSpringView(searchViewId));
-
+ absorbSwipeUpVelocity(Math.abs(
+ Math.round(velocity * FLING_VELOCITY_MULTIPLIER)));
shouldSpring = false;
}
}
@@ -699,8 +667,7 @@
applyPadding();
setupOverlay();
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- recyclerView.addItemDecoration(new AllAppsSectionDecorator(
- AllAppsContainerView.this));
+ recyclerView.addItemDecoration(mSearchAdapterProvider.getDecorator());
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index bb175ea..5b4c4c5 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -42,7 +42,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.PackageManagerHelper;
@@ -108,7 +107,7 @@
// The index of this app not including sections
public int appIndex = -1;
// Search section associated to result
- public SectionDecorationInfo sectionDecorationInfo = null;
+ public DecorationInfo decorationInfo = null;
/**
* Factory method for AppIcon AdapterItem
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
deleted file mode 100644
index 0bd2f44..0000000
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2020 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.allapps;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.view.View;
-
-import androidx.annotation.Nullable;
-import androidx.core.graphics.ColorUtils;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
-import com.android.launcher3.util.Themes;
-
-import java.util.List;
-
-/**
- * ItemDecoration class that groups items in {@link AllAppsRecyclerView}
- */
-public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
-
- private final AllAppsContainerView mAppsView;
-
- AllAppsSectionDecorator(AllAppsContainerView appsContainerView) {
- mAppsView = appsContainerView;
- }
-
- @Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
- List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
- SearchAdapterProvider adapterProvider = mAppsView.getSearchAdapterProvider();
- for (int i = 0; i < parent.getChildCount(); i++) {
- View view = parent.getChildAt(i);
- int position = parent.getChildAdapterPosition(view);
- AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
- if (adapterItem.sectionDecorationInfo != null) {
- SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
- SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
- if (decorationHandler != null) {
- if (view.equals(adapterProvider.getHighlightedItem())) {
- decorationHandler.onFocusDraw(c, view);
- } else {
- decorationHandler.onGroupDraw(c, view);
- }
- }
- }
- }
- }
-
- /**
- * Handles grouping and drawing of items in the same all apps sections.
- */
- public static class SectionDecorationHandler {
- protected RectF mBounds = new RectF();
- private final boolean mIsFullWidth;
- private final float mRadius;
-
- protected final int mFocusColor; // main focused item color
- protected final int mFillcolor; // grouping color
-
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private final boolean mIsTopRound;
- private final boolean mIsBottomRound;
- private float[] mCorners;
- private float mFillSpacing;
-
- public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha,
- boolean isTopRound, boolean isBottomRound) {
-
- mIsFullWidth = isFullWidth;
- int endScrim = Themes.getColorBackground(context);
- mFillcolor = ColorUtils.setAlphaComponent(endScrim, fillAlpha);
- mFocusColor = endScrim;
-
- mIsTopRound = isTopRound;
- mIsBottomRound = isBottomRound;
-
- mRadius = context.getResources().getDimensionPixelSize(
- R.dimen.search_decoration_corner_radius);
- mFillSpacing = context.getResources().getDimensionPixelSize(
- R.dimen.search_decoration_padding);
- mCorners = new float[]{
- mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top left radius in px
- mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top right radius in px
- mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0, // Bottom right
- mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0 // Bottom left
- };
-
- }
-
- /**
- * Draw bounds onto canvas.
- */
- public void onGroupDraw(Canvas canvas, View view) {
- if (view == null) return;
- mPaint.setColor(mFillcolor);
- mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
- onDraw(canvas);
- }
-
- /**
- * Draw the bound of the view to the canvas.
- */
- public void onFocusDraw(Canvas canvas, @Nullable View view) {
- if (view == null) {
- return;
- }
- mPaint.setColor(mFocusColor);
- mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
- onDraw(canvas);
- }
-
-
- private void onDraw(Canvas canvas) {
- final Path path = new Path();
- RectF finalBounds = new RectF(mBounds.left + mFillSpacing,
- mBounds.top + mFillSpacing,
- mBounds.right - mFillSpacing,
- mBounds.bottom - mFillSpacing);
- path.addRoundRect(finalBounds, mCorners, Path.Direction.CW);
- canvas.drawPath(path, mPaint);
- }
-
- /**
- * Reset view bounds to empty.
- */
- public void reset() {
- mBounds.setEmpty();
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 16ecd58..c21d774 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -110,7 +110,6 @@
setScrollRangeDelta(mScrollRangeDelta);
if (mIsVerticalLayout) {
- mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(1);
mLauncher.getHotseat().setTranslationY(0);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
}
@@ -128,7 +127,7 @@
mProgress = progress;
mScrimView.setProgress(progress);
- mAppsView.setTranslationY(progress * mShiftRange);
+ mAppsView.setTranslationY(mProgress * mShiftRange);
}
public float getProgress() {
@@ -155,19 +154,12 @@
StateAnimationConfig config, PendingAnimation builder) {
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
- if (!config.onlyPlayAtomicComponent()) {
- setAlphas(toState, config, builder);
- }
+ setAlphas(toState, config, builder);
// Fail fast
onProgressAnimationEnd();
return;
}
- if (config.onlyPlayAtomicComponent()) {
- // There is no atomic component for the all apps transition, so just return early.
- return;
- }
-
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index fefd97a..6957850 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -20,7 +20,6 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -288,11 +287,6 @@
mFastScrollerSections.clear();
mAdapterItems.clear();
- SectionDecorationInfo appSection = new SectionDecorationInfo();
- appSection.setDecorationHandler(
- new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true,
- 0, false, false));
-
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
// ordered set of sections
@@ -313,9 +307,7 @@
if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
lastFastScrollerSectionInfo.fastScrollToItem = appItem;
}
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- appItem.sectionDecorationInfo = appSection;
- }
+
mAdapterItems.add(appItem);
}
} else {
diff --git a/src/com/android/launcher3/util/SafeCloseable.java b/src/com/android/launcher3/allapps/DecorationInfo.java
similarity index 69%
rename from src/com/android/launcher3/util/SafeCloseable.java
rename to src/com/android/launcher3/allapps/DecorationInfo.java
index ba8ee04..50b250c 100644
--- a/src/com/android/launcher3/util/SafeCloseable.java
+++ b/src/com/android/launcher3/allapps/DecorationInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -13,14 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.launcher3.allapps;
-package com.android.launcher3.util;
-
-/**
- * Extension of closeable which does not throw an exception
- */
-public interface SafeCloseable extends AutoCloseable {
-
- @Override
- void close();
+public class DecorationInfo {
}
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 13ddc12..16ae250 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -72,8 +72,9 @@
@Override
public void setInsets(Rect insets) {
super.setInsets(insets);
- mLauncher.getAllAppsController()
- .setScrollRangeDelta(mSearchUiManager.getScrollRangeDelta(insets));
+ int allAppsStartingPositionY = mLauncher.getDeviceProfile().availableHeightPx
+ - mLauncher.getDeviceProfile().allAppsOpenVerticalTranslate;
+ mLauncher.getAllAppsController().setScrollRangeDelta(allAppsStartingPositionY);
}
@Override
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 0a2dea9..924a392 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-import android.graphics.Rect;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
@@ -44,16 +43,6 @@
default void preDispatchKeyEvent(KeyEvent keyEvent) { };
/**
- * Returns the vertical shift for the all-apps view, so that it aligns with the hotseat.
- */
- float getScrollRangeDelta(Rect insets);
-
- /**
- * Called when activity is destroyed. Used to close search system services
- */
- default void destroySearch() { }
-
- /**
* @return the edit text object
*/
@Nullable
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index bfcc1c7..a8185d6 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -36,14 +36,12 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Insettable;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.SearchUiManager;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchCallback;
import java.util.ArrayList;
@@ -136,7 +134,7 @@
mApps = appsView.getApps();
mAppsView = appsView;
mSearchBarController.initialize(
- new DefaultAppSearchAlgorithm(mLauncher, LauncherAppState.getInstance(mLauncher)),
+ new DefaultAppSearchAlgorithm(mLauncher),
this, mLauncher, this);
}
@@ -211,16 +209,6 @@
}
@Override
- public float getScrollRangeDelta(Rect insets) {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()
- || FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- return 0;
- } else {
- return insets.bottom + insets.top;
- }
- }
-
- @Override
public ExtendedEditText getEditText() {
return this;
}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
deleted file mode 100644
index 34895ed..0000000
--- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2020 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.allapps.search;
-
-import android.content.Context;
-import android.os.CancellationSignal;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.search.StringMatcherUtility;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * A device search section for handling app searches
- */
-public class AppsSearchPipeline implements SearchPipeline {
-
- private static final int MAX_RESULTS_COUNT = 5;
-
- private final SectionDecorationInfo mSearchSectionInfo;
- private final LauncherAppState mLauncherAppState;
-
- public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) {
- mLauncherAppState = launcherAppState;
- mSearchSectionInfo = new SectionDecorationInfo();
- mSearchSectionInfo.setDecorationHandler(
- new SectionDecorationHandler(context, true, 0, true, true));
- }
-
- @Override
- public void query(String input, Consumer<ArrayList<AdapterItem>> callback,
- CancellationSignal cancellationSignal) {
- mLauncherAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- List<AppInfo> matchingResults = getTitleMatchResult(apps.data, input);
- callback.accept(getAdapterItems(matchingResults));
- }
- });
- }
-
- /**
- * Filters {@link AppInfo}s matching specified query
- */
- public static ArrayList<AppInfo> getTitleMatchResult(List<AppInfo> apps, String query) {
- // Do an intersection of the words in the query and each title, and filter out all the
- // apps that don't match all of the words in the query.
- final String queryTextLower = query.toLowerCase();
- final ArrayList<AppInfo> result = new ArrayList<>();
- StringMatcherUtility.StringMatcher matcher =
- StringMatcherUtility.StringMatcher.getInstance();
- for (AppInfo info : apps) {
- if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) {
- result.add(info);
- }
- }
- return result;
- }
-
- private ArrayList<AdapterItem> getAdapterItems(List<AppInfo> matchingApps) {
- ArrayList<AdapterItem> items = new ArrayList<>();
- for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) {
- AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i);
- appItem.sectionDecorationInfo = mSearchSectionInfo;
- items.add(appItem);
- }
-
- return items;
- }
-}
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index a386ef8..1f854c6 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -15,25 +15,39 @@
*/
package com.android.launcher3.allapps.search;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
import android.content.Context;
import android.os.Handler;
+import androidx.annotation.AnyThread;
+
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import com.android.launcher3.model.AllAppsList;
+import com.android.launcher3.model.BaseModelUpdateTask;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.search.StringMatcherUtility;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* The default search implementation.
*/
public class DefaultAppSearchAlgorithm implements SearchAlgorithm<AdapterItem> {
- protected final Handler mResultHandler;
- private final AppsSearchPipeline mAppsSearchPipeline;
+ private static final int MAX_RESULTS_COUNT = 5;
- public DefaultAppSearchAlgorithm(Context context, LauncherAppState launcherAppState) {
- mResultHandler = new Handler();
- mAppsSearchPipeline = new AppsSearchPipeline(context, launcherAppState);
+ private final LauncherAppState mAppState;
+ private final Handler mResultHandler;
+
+ public DefaultAppSearchAlgorithm(Context context) {
+ mAppState = LauncherAppState.getInstance(context);
+ mResultHandler = new Handler(MAIN_EXECUTOR.getLooper());
}
@Override
@@ -44,11 +58,38 @@
}
@Override
- public void doSearch(final String query,
- final SearchCallback<AdapterItem> callback) {
- mAppsSearchPipeline.query(query,
- results -> mResultHandler.post(
- () -> callback.onSearchResult(query, results)),
- null);
+ public void doSearch(String query, SearchCallback<AdapterItem> callback) {
+ mAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() {
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query);
+ mResultHandler.post(() -> callback.onSearchResult(query, result));
+ }
+ });
+ }
+
+ /**
+ * Filters {@link AppInfo}s matching specified query
+ */
+ @AnyThread
+ public static ArrayList<AdapterItem> getTitleMatchResult(List<AppInfo> apps, String query) {
+ // Do an intersection of the words in the query and each title, and filter out all the
+ // apps that don't match all of the words in the query.
+ final String queryTextLower = query.toLowerCase();
+ final ArrayList<AdapterItem> result = new ArrayList<>();
+ StringMatcherUtility.StringMatcher matcher =
+ StringMatcherUtility.StringMatcher.getInstance();
+
+ int resultCount = 0;
+ int total = apps.size();
+ for (int i = 0; i < total && resultCount < MAX_RESULTS_COUNT; i++) {
+ AppInfo info = apps.get(i);
+ if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) {
+ AdapterItem appItem = AdapterItem.asApp(resultCount, "", info, resultCount);
+ result.add(appItem);
+ resultCount++;
+ }
+ }
+ return result;
}
}
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index ba895ed..ef62da4 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -15,12 +15,17 @@
*/
package com.android.launcher3.allapps.search;
+import android.graphics.Canvas;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.model.data.ItemInfo;
@@ -29,10 +34,19 @@
*/
public class DefaultSearchAdapterProvider extends SearchAdapterProvider {
+ private final RecyclerView.ItemDecoration mDecoration;
private View mHighlightedView;
- public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) {
- super(launcher);
+ public DefaultSearchAdapterProvider(BaseDraggingActivity launcher,
+ AllAppsContainerView appsContainerView) {
+ super(launcher, appsContainerView);
+ mDecoration = new RecyclerView.ItemDecoration() {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent,
+ @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+ };
}
@Override
@@ -67,4 +81,9 @@
public View getHighlightedItem() {
return mHighlightedView;
}
+
+ @Override
+ public RecyclerView.ItemDecoration getDecorator() {
+ return mDecoration;
+ }
}
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index a650a7d..cefb8cb 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -21,7 +21,10 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
/**
@@ -31,7 +34,7 @@
protected final BaseDraggingActivity mLauncher;
- public SearchAdapterProvider(BaseDraggingActivity launcher) {
+ public SearchAdapterProvider(BaseDraggingActivity launcher, AllAppsContainerView appsView) {
mLauncher = launcher;
}
@@ -72,7 +75,7 @@
}
/**
- * handles selection event on search adapter item. Returns false if provider can not handle
+ * Handles selection event on search adapter item. Returns false if provider can not handle
* event
*/
public abstract boolean launchHighlightedItem();
@@ -82,5 +85,8 @@
*/
public abstract View getHighlightedItem();
-
+ /**
+ * Returns the item decorator.
+ */
+ public abstract RecyclerView.ItemDecoration getDecorator();
}
diff --git a/src/com/android/launcher3/allapps/search/SearchPipeline.java b/src/com/android/launcher3/allapps/search/SearchPipeline.java
deleted file mode 100644
index 3516a41..0000000
--- a/src/com/android/launcher3/allapps/search/SearchPipeline.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2020 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.allapps.search;
-
-import android.os.CancellationSignal;
-
-import com.android.launcher3.allapps.AllAppsGridAdapter;
-
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-/**
- * An interface for handling search within pipeline
- */
-// Remove when System Service API is added.
-public interface SearchPipeline {
-
- /**
- * Perform query
- */
- void query(String input,
- Consumer<ArrayList<AllAppsGridAdapter.AdapterItem>> callback,
- CancellationSignal cancellationSignal);
-}
diff --git a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
deleted file mode 100644
index 56dd63c..0000000
--- a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2020 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.allapps.search;
-
-import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
-
-/**
- * Info class for a search section that is primarily used for decoration.
- */
-public class SectionDecorationInfo {
- public static final int GROUPING = 1 << 1;
-
- private String mSectionId;
- private SectionDecorationHandler mDecorationHandler;
-
- public SectionDecorationInfo() {
- this(null);
- }
-
- public SectionDecorationInfo(String sectionId) {
- mSectionId = sectionId;
- }
-
- public void setDecorationHandler(SectionDecorationHandler sectionDecorationHandler) {
- mDecorationHandler = sectionDecorationHandler;
- }
-
- public SectionDecorationHandler getDecorationHandler() {
- return mDecorationHandler;
- }
-
- /**
- * Returns the section's ID
- */
- public String getSectionId() {
- return mSectionId == null ? "" : mSectionId;
- }
-}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7f76d27..6331ef2 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -85,7 +85,7 @@
"ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations.");
public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag(
- "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
+ "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview");
// Keep as DeviceFlag to allow remote disable in emergency.
public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
@@ -93,7 +93,11 @@
public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
- "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps");
+ "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
+
+ public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
+ "ENABLE_PEOPLE_TILE_PREVIEW", false,
+ "Experimental: Shows conversation shortcuts on home screen as search results");
public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
"FOLDER_NAME_SUGGEST", true,
@@ -187,7 +191,7 @@
"EXPANDED_SMARTSPACE", false, "Expands smartspace height to two rows. "
+ "Any apps occupying the first row will be removed from workspace.");
- public static final BooleanFlag ENABLE_FOUR_COLUMNS = new DeviceFlag(
+ public static final DeviceFlag ENABLE_FOUR_COLUMNS = new DeviceFlag(
"ENABLE_FOUR_COLUMNS", false, "Uses 4 columns in launcher grid."
+ "Warning: This will permanently alter your home screen items and is not reversible.");
@@ -218,6 +222,9 @@
public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
"ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
+ public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
+ "Sends a notification whenever launcher encounters an uncaught exception.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
@@ -227,6 +234,12 @@
}
}
+ public static void removeFlag(DebugFlag flag) {
+ synchronized (sDebugFlags) {
+ sDebugFlags.remove(flag);
+ }
+ }
+
static List<DebugFlag> getDebugFlags() {
synchronized (sDebugFlags) {
return new ArrayList<>(sDebugFlags);
@@ -304,6 +317,15 @@
.getBoolean(key, defaultValue);
}
+ /**
+ * Resets value to default value.
+ */
+ public void reset(Context context) {
+ mCurrentValue = defaultValue;
+ context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ .edit().putBoolean(key, defaultValue).apply();
+ }
+
@Override
protected StringBuilder appendProps(StringBuilder src) {
return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue);
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 5cd95dc..7b32bbf 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -27,15 +27,21 @@
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-/** A drawable which renders {@link LauncherAppWidgetHostView} to a canvas. */
+/**
+ * A drawable which renders {@link LauncherAppWidgetHostView} to a canvas.
+ *
+ * TODO(b/183609936) Stop using that class and remove it.
+ */
public final class AppWidgetHostViewDrawable extends Drawable {
private final LauncherAppWidgetHostView mAppWidgetHostView;
private Paint mPaint = new Paint();
private final Path mClipPath;
+ private final boolean mWasAttached;
public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
mAppWidgetHostView = appWidgetHostView;
+ mWasAttached = appWidgetHostView.isAttachedToWindow();
Path clipPath = null;
if (appWidgetHostView.getClipToOutline()) {
Outline outline = new Outline();
@@ -56,7 +62,12 @@
if (mClipPath != null) {
canvas.clipPath(mClipPath);
}
- mAppWidgetHostView.draw(canvas);
+ // If the view was never attached, or is current attached, then draw. Otherwise do not try
+ // to draw, or we might trigger bugs with items that get drawn while requiring the view to
+ // be attached.
+ if (!mWasAttached || mAppWidgetHostView.isAttachedToWindow()) {
+ mAppWidgetHostView.draw(canvas);
+ }
canvas.restoreToCount(saveCount);
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index e2816f4..0f26ff4 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -44,7 +44,6 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.FirstFrameAnimatorHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
@@ -52,6 +51,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statemanager.StateManager.StateListener;
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index f543e47..29e7c18 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -28,7 +28,6 @@
import android.os.Build;
import android.os.Process;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
@@ -78,7 +77,7 @@
Drawable d = mContext.getSystemService(LauncherApps.class)
.getShortcutIconDrawable(mInfo, LauncherAppState.getIDP(mContext).fillResIconDpi);
if (d == null) {
- d = new FastBitmapDrawable(cache.getDefaultIcon(Process.myUserHandle()));
+ d = cache.getDefaultIcon(Process.myUserHandle()).newIcon(mContext);
}
return d;
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index ec7155c..a1b7997 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -745,6 +745,10 @@
if (mIsAnimatingClosed) {
return;
}
+
+ mContent.completePendingPageChanges();
+ mContent.snapToPageImmediately(mContent.getDestinationPage());
+
if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
mCurrentAnimator.cancel();
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 0235dfa..c1f4643 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -483,7 +483,7 @@
icon.verifyHighRes();
// Set the callback back to the actual icon, in case
// it was captured by the FolderIcon
- Drawable d = icon.getCompoundDrawables()[1];
+ Drawable d = icon.getIcon();
if (d != null) {
d.setCallback(icon);
}
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 9ae7faf..8244f01 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -16,7 +16,6 @@
package com.android.launcher3.folder;
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
@@ -33,10 +32,10 @@
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
import android.view.View;
-import android.widget.TextView;
import androidx.annotation.NonNull;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -113,7 +112,7 @@
}
Drawable prepareCreateAnimation(final View destView) {
- Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
+ Drawable animateDrawable = ((BubbleTextView) destView).getIcon();
computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
destView.getMeasuredWidth());
mReferenceDrawable = animateDrawable;
@@ -401,7 +400,7 @@
drawable.setLevel(item.getProgressLevel());
p.drawable = drawable;
} else {
- p.drawable = newIcon(mContext, item);
+ p.drawable = item.newIcon(mContext);
}
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
p.item = item;
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 9bc5444..0e61b98 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -30,13 +30,13 @@
import android.view.View;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.AppWidgetHostViewDrawable;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index cb42e7a..911f8c3 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -90,7 +90,10 @@
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
- result.add(new GridOption(getContext(), Xml.asAttributeSet(parser)));
+ GridOption option = new GridOption(getContext(), Xml.asAttributeSet(parser));
+ if (option.visible) {
+ result.add(option);
+ }
}
}
} catch (IOException | XmlPullParserException e) {
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
deleted file mode 100644
index 5872689..0000000
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 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.graphics;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-
-/**
- * Utility class which draws a bitmap by dissecting it into 3 segments and stretching
- * the middle segment.
- */
-public class NinePatchDrawHelper {
-
- // The extra width used for the bitmap. This portion of the bitmap is stretched to match the
- // width of the draw region. Randomly chosen, any value > 4 will be sufficient.
- public static final int EXTENSION_PX = 20;
-
- private final Rect mSrc = new Rect();
- private final RectF mDst = new RectF();
- // Enable filtering to always get a nice edge. This avoids jagged line, when bitmap is
- // translated by half pixel.
- public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
- /**
- * Draws the bitmap split into three parts horizontally, with the middle part having width
- * as {@link #EXTENSION_PX} in the center of the bitmap.
- */
- public void draw(Bitmap bitmap, Canvas canvas, float left, float top, float right) {
- int height = bitmap.getHeight();
-
- mSrc.top = 0;
- mSrc.bottom = height;
- mDst.top = top;
- mDst.bottom = top + height;
- draw3Patch(bitmap, canvas, left, right);
- }
-
-
- /**
- * Draws the bitmap split horizontally into 3 parts (same as {@link #draw}) and split
- * vertically into two parts, bottom part of size {@link #EXTENSION_PX} / 2 which is
- * stretched vertically.
- */
- public void drawVerticallyStretched(Bitmap bitmap, Canvas canvas, float left, float top,
- float right, float bottom) {
- draw(bitmap, canvas, left, top, right);
-
- // Draw bottom stretched region.
- int height = bitmap.getHeight();
- mSrc.top = height - EXTENSION_PX / 4;
- mSrc.bottom = height;
- mDst.top = top + height;
- mDst.bottom = bottom;
- draw3Patch(bitmap, canvas, left, right);
- }
-
-
-
- private void draw3Patch(Bitmap bitmap, Canvas canvas, float left, float right) {
- int width = bitmap.getWidth();
- int halfWidth = width / 2;
-
- // Draw left edge
- drawRegion(bitmap, canvas, 0, halfWidth, left, left + halfWidth);
-
- // Draw right edge
- drawRegion(bitmap, canvas, halfWidth, width, right - halfWidth, right);
-
- // Draw middle stretched region
- int halfExt = EXTENSION_PX / 4;
- drawRegion(bitmap, canvas, halfWidth - halfExt, halfWidth + halfExt,
- left + halfWidth, right - halfWidth);
- }
-
- private void drawRegion(Bitmap bitmap, Canvas c,
- int srcLeft, int srcRight, float dstLeft, float dstRight) {
- mSrc.left = srcLeft;
- mSrc.right = srcRight;
-
- mDst.left = dstLeft;
- mDst.right = dstRight;
- c.drawBitmap(bitmap, mSrc, mDst, paint);
- }
-}
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
index 53303db..7aadb96 100644
--- a/src/com/android/launcher3/graphics/OverviewScrim.java
+++ b/src/com/android/launcher3/graphics/OverviewScrim.java
@@ -25,6 +25,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
+
/**
* View scrim which draws behind overview (recent apps).
*/
@@ -52,7 +56,7 @@
public OverviewScrim(View view) {
super(view);
- onExtractedColorsChanged(mWallpaperColorInfo);
+ mScrimColor = Themes.getAttrColor(view.getContext(), R.attr.allAppsScrimColor);
}
/**
@@ -62,6 +66,13 @@
mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
}
+ /**
+ * @param view The view we want the scrim to be behind
+ */
+ public void updateStableScrimmedView(View view) {
+ mStableScrimmedView = view;
+ }
+
public void updateCurrentScrimmedView(ViewGroup root) {
// Find the lowest view that is at or above the view we want to show the scrim behind.
mCurrentScrimmedView = mStableScrimmedView;
@@ -74,6 +85,11 @@
}
}
+ @Override
+ public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+ // No super, don't respond to wallpaper colors, follow device ones instead
+ }
+
/**
* @return The view to draw the scrim behind, or null if all visible views should be scrimmed.
*/
diff --git a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
deleted file mode 100644
index b6d25c4..0000000
--- a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.graphics;
-
-import static androidx.core.graphics.ColorUtils.compositeColors;
-
-import static com.android.launcher3.graphics.IconShape.getShapePath;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-
-import androidx.core.graphics.ColorUtils;
-
-import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.util.Themes;
-
-/**
- * Subclass which draws a placeholder icon when the actual icon is not yet loaded
- */
-public class PlaceHolderIconDrawable extends FastBitmapDrawable {
-
- // Path in [0, 100] bounds.
- private final Path mProgressPath;
-
- public PlaceHolderIconDrawable(BitmapInfo info, Context context) {
- super(info);
-
- mProgressPath = getShapePath();
- mPaint.setColor(compositeColors(
- Themes.getAttrColor(context, R.attr.loadingIconColor), info.color));
- }
-
- @Override
- protected void drawInternal(Canvas canvas, Rect bounds) {
- int saveCount = canvas.save();
- canvas.translate(bounds.left, bounds.top);
- canvas.scale(bounds.width() / 100f, bounds.height() / 100f);
- canvas.drawPath(mProgressPath, mPaint);
- canvas.restoreToCount(saveCount);
- }
-
- /** Updates this placeholder to {@code newIcon} with animation. */
- public void animateIconUpdate(Drawable newIcon) {
- int placeholderColor = mPaint.getColor();
- int originalAlpha = Color.alpha(placeholderColor);
-
- ValueAnimator iconUpdateAnimation = ValueAnimator.ofInt(originalAlpha, 0);
- iconUpdateAnimation.setDuration(375);
- iconUpdateAnimation.addUpdateListener(valueAnimator -> {
- int newAlpha = (int) valueAnimator.getAnimatedValue();
- int newColor = ColorUtils.setAlphaComponent(placeholderColor, newAlpha);
-
- newIcon.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_ATOP));
- });
- iconUpdateAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- newIcon.setColorFilter(null);
- }
- });
- iconUpdateAnimation.start();
- }
-
-}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index ce824df..ac0ec5f 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -37,8 +37,8 @@
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.Themes;
diff --git a/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/src/com/android/launcher3/icons/ClockDrawableWrapper.java
deleted file mode 100644
index 1bd252b..0000000
--- a/src/com/android/launcher3/icons/ClockDrawableWrapper.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2019 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.icons;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.launcher3.FastBitmapDrawable;
-
-import java.util.Calendar;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Wrapper over {@link AdaptiveIconDrawable} to intercept icon flattening logic for dynamic
- * clock icons
- */
-@TargetApi(Build.VERSION_CODES.O)
-public class ClockDrawableWrapper extends AdaptiveIconDrawable implements BitmapInfo.Extender {
-
- private static final String TAG = "ClockDrawableWrapper";
-
- private static final boolean DISABLE_SECONDS = true;
-
- // Time after which the clock icon should check for an update. The actual invalidate
- // will only happen in case of any change.
- public static final long TICK_MS = DISABLE_SECONDS ? TimeUnit.MINUTES.toMillis(1) : 200L;
-
- private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
- private static final String ROUND_ICON_METADATA_KEY = LAUNCHER_PACKAGE
- + ".LEVEL_PER_TICK_ICON_ROUND";
- private static final String HOUR_INDEX_METADATA_KEY = LAUNCHER_PACKAGE + ".HOUR_LAYER_INDEX";
- private static final String MINUTE_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
- + ".MINUTE_LAYER_INDEX";
- private static final String SECOND_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
- + ".SECOND_LAYER_INDEX";
- private static final String DEFAULT_HOUR_METADATA_KEY = LAUNCHER_PACKAGE
- + ".DEFAULT_HOUR";
- private static final String DEFAULT_MINUTE_METADATA_KEY = LAUNCHER_PACKAGE
- + ".DEFAULT_MINUTE";
- private static final String DEFAULT_SECOND_METADATA_KEY = LAUNCHER_PACKAGE
- + ".DEFAULT_SECOND";
-
- /* Number of levels to jump per second for the second hand */
- private static final int LEVELS_PER_SECOND = 10;
-
- public static final int INVALID_VALUE = -1;
-
- private final AnimationInfo mAnimationInfo = new AnimationInfo();
- private int mTargetSdkVersion;
-
- public ClockDrawableWrapper(AdaptiveIconDrawable base) {
- super(base.getBackground(), base.getForeground());
- }
-
- /**
- * Loads and returns the wrapper from the provided package, or returns null
- * if it is unable to load.
- */
- public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi) {
- try {
- PackageManager pm = context.getPackageManager();
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
- final Bundle metadata = appInfo.metaData;
- if (metadata == null) {
- return null;
- }
- int drawableId = metadata.getInt(ROUND_ICON_METADATA_KEY, 0);
- if (drawableId == 0) {
- return null;
- }
-
- Drawable drawable = pm.getResourcesForApplication(appInfo).getDrawableForDensity(
- drawableId, iconDpi).mutate();
- if (!(drawable instanceof AdaptiveIconDrawable)) {
- return null;
- }
-
- ClockDrawableWrapper wrapper =
- new ClockDrawableWrapper((AdaptiveIconDrawable) drawable);
- wrapper.mTargetSdkVersion = appInfo.targetSdkVersion;
- AnimationInfo info = wrapper.mAnimationInfo;
-
- info.baseDrawableState = drawable.getConstantState();
-
- info.hourLayerIndex = metadata.getInt(HOUR_INDEX_METADATA_KEY, INVALID_VALUE);
- info.minuteLayerIndex = metadata.getInt(MINUTE_INDEX_METADATA_KEY, INVALID_VALUE);
- info.secondLayerIndex = metadata.getInt(SECOND_INDEX_METADATA_KEY, INVALID_VALUE);
-
- info.defaultHour = metadata.getInt(DEFAULT_HOUR_METADATA_KEY, 0);
- info.defaultMinute = metadata.getInt(DEFAULT_MINUTE_METADATA_KEY, 0);
- info.defaultSecond = metadata.getInt(DEFAULT_SECOND_METADATA_KEY, 0);
-
- LayerDrawable foreground = (LayerDrawable) wrapper.getForeground();
- int layerCount = foreground.getNumberOfLayers();
- if (info.hourLayerIndex < 0 || info.hourLayerIndex >= layerCount) {
- info.hourLayerIndex = INVALID_VALUE;
- }
- if (info.minuteLayerIndex < 0 || info.minuteLayerIndex >= layerCount) {
- info.minuteLayerIndex = INVALID_VALUE;
- }
- if (info.secondLayerIndex < 0 || info.secondLayerIndex >= layerCount) {
- info.secondLayerIndex = INVALID_VALUE;
- } else if (DISABLE_SECONDS) {
- foreground.setDrawable(info.secondLayerIndex, null);
- info.secondLayerIndex = INVALID_VALUE;
- }
- return wrapper;
- } catch (Exception e) {
- Log.d(TAG, "Unable to load clock drawable info", e);
- }
- return null;
- }
-
- @Override
- public BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory) {
- iconFactory.disableColorExtraction();
- float [] scale = new float[1];
- AdaptiveIconDrawable background = new AdaptiveIconDrawable(
- getBackground().getConstantState().newDrawable(), null);
- BitmapInfo bitmapInfo = iconFactory.createBadgedIconBitmap(background,
- Process.myUserHandle(), mTargetSdkVersion, false, scale);
-
- return new ClockBitmapInfo(bitmap, color, scale[0], mAnimationInfo, bitmapInfo.icon);
- }
-
- @Override
- public void prepareToDrawOnUi() {
- mAnimationInfo.applyTime(Calendar.getInstance(), (LayerDrawable) getForeground());
- }
-
- private static class AnimationInfo {
-
- public ConstantState baseDrawableState;
-
- public int hourLayerIndex;
- public int minuteLayerIndex;
- public int secondLayerIndex;
- public int defaultHour;
- public int defaultMinute;
- public int defaultSecond;
-
- boolean applyTime(Calendar time, LayerDrawable foregroundDrawable) {
- time.setTimeInMillis(System.currentTimeMillis());
-
- // We need to rotate by the difference from the default time if one is specified.
- int convertedHour = (time.get(Calendar.HOUR) + (12 - defaultHour)) % 12;
- int convertedMinute = (time.get(Calendar.MINUTE) + (60 - defaultMinute)) % 60;
- int convertedSecond = (time.get(Calendar.SECOND) + (60 - defaultSecond)) % 60;
-
- boolean invalidate = false;
- if (hourLayerIndex != INVALID_VALUE) {
- final Drawable hour = foregroundDrawable.getDrawable(hourLayerIndex);
- if (hour.setLevel(convertedHour * 60 + time.get(Calendar.MINUTE))) {
- invalidate = true;
- }
- }
-
- if (minuteLayerIndex != INVALID_VALUE) {
- final Drawable minute = foregroundDrawable.getDrawable(minuteLayerIndex);
- if (minute.setLevel(time.get(Calendar.HOUR) * 60 + convertedMinute)) {
- invalidate = true;
- }
- }
-
- if (secondLayerIndex != INVALID_VALUE) {
- final Drawable second = foregroundDrawable.getDrawable(secondLayerIndex);
- if (second.setLevel(convertedSecond * LEVELS_PER_SECOND)) {
- invalidate = true;
- }
- }
-
- return invalidate;
- }
- }
-
- private static class ClockBitmapInfo extends BitmapInfo implements FastBitmapDrawable.Factory {
-
- public final float scale;
- public final int offset;
- public final AnimationInfo animInfo;
- public final Bitmap mFlattenedBackground;
-
- ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
- Bitmap background) {
- super(icon, color);
- this.scale = scale;
- this.animInfo = animInfo;
- this.offset = (int) Math.ceil(ShadowGenerator.BLUR_FACTOR * icon.getWidth());
- this.mFlattenedBackground = background;
- }
-
- @Override
- public FastBitmapDrawable newDrawable() {
- return new ClockIconDrawable(this);
- }
- }
-
- private static class ClockIconDrawable extends FastBitmapDrawable implements Runnable {
-
- private final Calendar mTime = Calendar.getInstance();
-
- private final ClockBitmapInfo mInfo;
-
- private final AdaptiveIconDrawable mFullDrawable;
- private final LayerDrawable mForeground;
-
- ClockIconDrawable(ClockBitmapInfo clockInfo) {
- super(clockInfo);
-
- mInfo = clockInfo;
-
- mFullDrawable = (AdaptiveIconDrawable) mInfo.animInfo.baseDrawableState.newDrawable();
- mForeground = (LayerDrawable) mFullDrawable.getForeground();
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- super.onBoundsChange(bounds);
- mFullDrawable.setBounds(bounds);
- }
-
- @Override
- public void drawInternal(Canvas canvas, Rect bounds) {
- if (mInfo == null) {
- super.drawInternal(canvas, bounds);
- return;
- }
- // draw the background that is already flattened to a bitmap
- canvas.drawBitmap(mInfo.mFlattenedBackground, null, bounds, mPaint);
-
- // prepare and draw the foreground
- mInfo.animInfo.applyTime(mTime, mForeground);
-
- canvas.scale(mInfo.scale, mInfo.scale,
- bounds.exactCenterX() + mInfo.offset, bounds.exactCenterY() + mInfo.offset);
- canvas.clipPath(mFullDrawable.getIconMask());
- mForeground.draw(canvas);
-
- reschedule();
- }
-
- @Override
- protected void updateFilter() {
- super.updateFilter();
- mFullDrawable.setColorFilter(mPaint.getColorFilter());
- }
-
- @Override
- public void run() {
- if (mInfo.animInfo.applyTime(mTime, mForeground)) {
- invalidateSelf();
- } else {
- reschedule();
- }
- }
-
- @Override
- public boolean setVisible(boolean visible, boolean restart) {
- boolean result = super.setVisible(visible, restart);
- if (visible) {
- reschedule();
- } else {
- unscheduleSelf(this);
- }
- return result;
- }
-
- private void reschedule() {
- if (!isVisible()) {
- return;
- }
-
- unscheduleSelf(this);
- final long upTime = SystemClock.uptimeMillis();
- final long step = TICK_MS; /* tick every 200 ms */
- scheduleSelf(this, upTime - ((upTime % step)) + step);
- }
-
- @Override
- public ConstantState getConstantState() {
- return new ClockConstantState(mInfo, isDisabled());
- }
-
- private static class ClockConstantState extends FastBitmapConstantState {
-
- private final ClockBitmapInfo mInfo;
-
- ClockConstantState(ClockBitmapInfo info, boolean isDisabled) {
- super(info.icon, info.color, isDisabled);
- mInfo = info;
- }
-
- @Override
- public FastBitmapDrawable newDrawable() {
- ClockIconDrawable drawable = new ClockIconDrawable(mInfo);
- drawable.setIsDisabled(mIsDisabled);
- return drawable;
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/icons/IconProvider.java b/src/com/android/launcher3/icons/IconProvider.java
deleted file mode 100644
index 1468b27..0000000
--- a/src/com/android/launcher3/icons/IconProvider.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2019 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.icons;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Process;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo.Extender;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.SafeCloseable;
-
-import java.util.Calendar;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-
-/**
- * Class to handle icon loading from different packages
- */
-public class IconProvider {
-
- private static final String TAG = "IconProvider";
- private static final boolean DEBUG = false;
-
- private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons";
-
- private static final String SYSTEM_STATE_SEPARATOR = " ";
-
- // Default value returned if there are problems getting resources.
- private static final int NO_ID = 0;
-
- private static final BiFunction<LauncherActivityInfo, Integer, Drawable> LAI_LOADER =
- LauncherActivityInfo::getIcon;
-
- private static final BiFunction<ActivityInfo, PackageManager, Drawable> AI_LOADER =
- ActivityInfo::loadUnbadgedIcon;
-
-
- private final Context mContext;
- private final ComponentName mCalendar;
- private final ComponentName mClock;
-
- public IconProvider(Context context) {
- mContext = context;
- mCalendar = parseComponentOrNull(context, R.string.calendar_component_name);
- mClock = parseComponentOrNull(context, R.string.clock_component_name);
- }
-
- /**
- * Adds any modification to the provided systemState for dynamic icons. This system state
- * is used by caches to check for icon invalidation.
- */
- public String getSystemStateForPackage(String systemState, String packageName) {
- if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
- return systemState + SYSTEM_STATE_SEPARATOR + getDay();
- } else {
- return systemState;
- }
- }
-
- /**
- * Loads the icon for the provided LauncherActivityInfo such that it can be drawn directly
- * on the UI
- */
- public Drawable getIconForUI(LauncherActivityInfo info, int iconDpi) {
- Drawable icon = getIcon(info, iconDpi);
- if (icon instanceof BitmapInfo.Extender) {
- ((Extender) icon).prepareToDrawOnUi();
- }
- return icon;
- }
-
- /**
- * Loads the icon for the provided LauncherActivityInfo
- */
- public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
- return getIcon(info.getApplicationInfo().packageName, info.getUser(),
- info, iconDpi, LAI_LOADER);
- }
-
- /**
- * Loads the icon for the provided activity info
- */
- public Drawable getIcon(ActivityInfo info, UserHandle user) {
- return getIcon(info.applicationInfo.packageName, user, info, mContext.getPackageManager(),
- AI_LOADER);
- }
-
- private <T, P> Drawable getIcon(String packageName, UserHandle user, T obj, P param,
- BiFunction<T, P, Drawable> loader) {
- Drawable icon = null;
- if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
- icon = loadCalendarDrawable(0);
- } else if (mClock != null
- && mClock.getPackageName().equals(packageName)
- && Process.myUserHandle().equals(user)) {
- icon = loadClockDrawable(0);
- }
- return icon == null ? loader.apply(obj, param) : icon;
- }
-
- private Drawable loadCalendarDrawable(int iconDpi) {
- PackageManager pm = mContext.getPackageManager();
- try {
- final Bundle metadata = pm.getActivityInfo(
- mCalendar,
- PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA)
- .metaData;
- final Resources resources = pm.getResourcesForApplication(mCalendar.getPackageName());
- final int id = getDynamicIconId(metadata, resources);
- if (id != NO_ID) {
- if (DEBUG) Log.d(TAG, "Got icon #" + id);
- return resources.getDrawableForDensity(id, iconDpi, null /* theme */);
- }
- } catch (PackageManager.NameNotFoundException e) {
- if (DEBUG) {
- Log.d(TAG, "Could not get activityinfo or resources for package: "
- + mCalendar.getPackageName());
- }
- }
- return null;
- }
-
- private Drawable loadClockDrawable(int iconDpi) {
- return ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
- }
-
- protected boolean isClockIcon(ComponentKey key) {
- return mClock != null && mClock.equals(key.componentName)
- && Process.myUserHandle().equals(key.user);
- }
-
- /**
- * @param metadata metadata of the default activity of Calendar
- * @param resources from the Calendar package
- * @return the resource id for today's Calendar icon; 0 if resources cannot be found.
- */
- private int getDynamicIconId(Bundle metadata, Resources resources) {
- if (metadata == null) {
- return NO_ID;
- }
- String key = mCalendar.getPackageName() + ICON_METADATA_KEY_PREFIX;
- final int arrayId = metadata.getInt(key, NO_ID);
- if (arrayId == NO_ID) {
- return NO_ID;
- }
- try {
- return resources.obtainTypedArray(arrayId).getResourceId(getDay(), NO_ID);
- } catch (Resources.NotFoundException e) {
- if (DEBUG) {
- Log.d(TAG, "package defines '" + key + "' but corresponding array not found");
- }
- return NO_ID;
- }
- }
-
- /**
- * @return Today's day of the month, zero-indexed.
- */
- private int getDay() {
- return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
- }
-
-
- /**
- * Registers a callback to listen for calendar icon changes.
- * The callback receives the packageName for the calendar icon
- */
- public static SafeCloseable registerIconChangeListener(Context context,
- BiConsumer<String, UserHandle> callback, Handler handler) {
- ComponentName calendar = parseComponentOrNull(context, R.string.calendar_component_name);
- ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
-
- if (calendar == null && clock == null) {
- return () -> { };
- }
-
- BroadcastReceiver receiver = new DateTimeChangeReceiver(callback);
- final IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
- if (calendar != null) {
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_DATE_CHANGED);
- }
- context.registerReceiver(receiver, filter, null, handler);
-
- return () -> context.unregisterReceiver(receiver);
- }
-
- private static class DateTimeChangeReceiver extends BroadcastReceiver {
-
- private final BiConsumer<String, UserHandle> mCallback;
-
- DateTimeChangeReceiver(BiConsumer<String, UserHandle> callback) {
- mCallback = callback;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
- ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
- if (clock != null) {
- mCallback.accept(clock.getPackageName(), Process.myUserHandle());
- }
- }
-
- ComponentName calendar =
- parseComponentOrNull(context, R.string.calendar_component_name);
- if (calendar != null) {
- for (UserHandle user : UserCache.INSTANCE.get(context).getUserProfiles()) {
- mCallback.accept(calendar.getPackageName(), user);
- }
- }
-
- }
- }
-
- private static ComponentName parseComponentOrNull(Context context, int resId) {
- String cn = context.getString(resId);
- return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
-
- }
-}
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 70d1b48..e391d37 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.model;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.os.Process.myUserHandle;
import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
@@ -140,7 +142,7 @@
.putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
.putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
.putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0,
- new Intent(), PendingIntent.FLAG_ONE_SHOT)));
+ new Intent(), FLAG_ONE_SHOT | FLAG_IMMUTABLE)));
}
private static String getPackageName(ItemInfo info) {
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index d95e708..76b2ab0 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -23,6 +23,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.PackageManagerHelper;
@@ -216,4 +217,14 @@
* @return a copy of this
*/
public abstract ItemInfoWithIcon clone();
+
+
+ /**
+ * Returns a FastBitmapDrawable with the icon.
+ */
+ public FastBitmapDrawable newIcon(Context context) {
+ FastBitmapDrawable drawable = bitmap.newIcon(context);
+ drawable.setIsDisabled(isDisabled());
+ return drawable;
+ }
}
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index 80eeb22..d27d8c7 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -22,7 +22,6 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -86,9 +85,8 @@
mIsIconLarge = true;
}
if (mIconDrawable == null) {
- mIconDrawable = new BitmapDrawable(context.getResources(), LauncherAppState
- .getInstance(context).getIconCache()
- .getDefaultIcon(statusBarNotification.getUser()).icon);
+ mIconDrawable = LauncherAppState.getInstance(context).getIconCache()
+ .getDefaultIcon(statusBarNotification.getUser()).newIcon(context);
}
intent = notification.contentIntent;
autoCancel = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0;
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 2905dc3..e58f5fa 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -16,9 +16,9 @@
package com.android.launcher3.notification;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import android.annotation.TargetApi;
import android.app.Notification;
@@ -37,8 +37,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
-import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SettingsCache;
import java.util.ArrayList;
import java.util.Arrays;
@@ -213,7 +213,7 @@
mNotificationSettingsChangedListener = this::onNotificationSettingsChanged;
mSettingsCache.register(NOTIFICATION_BADGING_URI,
mNotificationSettingsChangedListener);
- mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+ onNotificationSettingsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
onNotificationFullRefresh();
}
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 7780894..6f9f0d7 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -40,6 +40,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -224,6 +225,7 @@
.map(recommendedWidget -> allWidgetItems.get(
new ComponentKey(recommendedWidget.getTargetComponent(),
recommendedWidget.user)))
+ .filter(Objects::nonNull)
.collect(Collectors.toList());
}
diff --git a/src/com/android/launcher3/settings/NotificationDotsPreference.java b/src/com/android/launcher3/settings/NotificationDotsPreference.java
index a354169..afcf882 100644
--- a/src/com/android/launcher3/settings/NotificationDotsPreference.java
+++ b/src/com/android/launcher3/settings/NotificationDotsPreference.java
@@ -17,6 +17,8 @@
import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
import static com.android.launcher3.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGS;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -24,6 +26,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.database.ContentObserver;
import android.os.Bundle;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -49,6 +52,14 @@
/** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
+ private final ContentObserver mListenerListObserver =
+ new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateUI();
+ }
+ };
+
public NotificationDotsPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -66,6 +77,29 @@
super(context);
}
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ SettingsCache.INSTANCE.get(getContext()).register(NOTIFICATION_BADGING_URI, this);
+ getContext().getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
+ false, mListenerListObserver);
+ updateUI();
+ }
+
+ private void updateUI() {
+ onSettingsChanged(SettingsCache.INSTANCE.get(getContext())
+ .getValue(NOTIFICATION_BADGING_URI));
+ }
+
+ @Override
+ public void onDetached() {
+ super.onDetached();
+ SettingsCache.INSTANCE.get(getContext()).unregister(NOTIFICATION_BADGING_URI, this);
+ getContext().getContentResolver().unregisterContentObserver(mListenerListObserver);
+
+ }
+
private void setWidgetFrameVisible(boolean isVisible) {
if (mWidgetFrameVisible != isVisible) {
mWidgetFrameVisible = isVisible;
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index f03065c..5b42ac7 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -18,8 +18,6 @@
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_ENABLED_LISTENERS;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
@@ -45,7 +43,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
/**
@@ -124,11 +121,8 @@
*/
public static class LauncherSettingsFragment extends PreferenceFragmentCompat {
- private SettingsCache mSettingsCache;
-
private String mHighLightKey;
private boolean mPreferenceHighlighted = false;
- private NotificationDotsPreference mNotificationSettingsChangedListener;
private Preference mDeveloperOptionPref;
@Override
@@ -172,22 +166,7 @@
protected boolean initPreference(Preference preference) {
switch (preference.getKey()) {
case NOTIFICATION_DOTS_PREFERENCE_KEY:
- if (WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS) {
- return false;
- }
-
- // Listen to system notification dot settings while this UI is active.
- mSettingsCache = SettingsCache.INSTANCE.get(getActivity());
- mNotificationSettingsChangedListener =
- ((NotificationDotsPreference) preference);
- mSettingsCache.register(NOTIFICATION_BADGING_URI,
- (NotificationDotsPreference) mNotificationSettingsChangedListener);
- // Also listen if notification permission changes
- mSettingsCache.register(NOTIFICATION_ENABLED_LISTENERS,
- mNotificationSettingsChangedListener);
- mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
- mSettingsCache.dispatchOnChange(NOTIFICATION_ENABLED_LISTENERS);
- return true;
+ return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;
case ALLOW_ROTATION_PREFERENCE_KEY:
if (getResources().getBoolean(R.bool.allow_rotation)) {
@@ -269,16 +248,5 @@
}
});
}
-
- @Override
- public void onDestroy() {
- if (mSettingsCache != null) {
- mSettingsCache.unregister(NOTIFICATION_BADGING_URI,
- mNotificationSettingsChangedListener);
- mSettingsCache.unregister(NOTIFICATION_ENABLED_LISTENERS,
- mNotificationSettingsChangedListener);
- }
- super.onDestroy();
- }
}
}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index 530aaed..cecbb0d 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -23,12 +23,12 @@
import android.graphics.drawable.Drawable;
import android.view.View;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
/**
* Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size.
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 51767e7..14ef2dc 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -18,7 +18,7 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
@@ -289,14 +289,14 @@
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
STATE_TYPE state, long duration) {
- return createAnimationToNewWorkspace(state, duration, ANIM_ALL_COMPONENTS);
+ return createAnimationToNewWorkspace(state, duration, 0 /* animFlags */);
}
public AnimatorPlaybackController createAnimationToNewWorkspace(
- STATE_TYPE state, long duration, @AnimationFlags int animComponents) {
+ STATE_TYPE state, long duration, @AnimationFlags int animFlags) {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = duration;
- config.animFlags = animComponents;
+ config.animFlags = animFlags;
return createAnimationToNewWorkspace(state, config);
}
@@ -312,7 +312,7 @@
private PendingAnimation createAnimationToNewWorkspaceInternal(final STATE_TYPE state) {
PendingAnimation builder = new PendingAnimation(mConfig.duration);
- if (mConfig.getAnimComponents() != 0) {
+ if (!mConfig.hasAnimationFlag(SKIP_ALL_ANIMATIONS)) {
for (StateHandler handler : getStateHandlers()) {
handler.setStateWithAnimation(state, mConfig, builder);
}
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index eb2c551..76f89bc 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -31,7 +31,11 @@
| FLAG_HAS_SYS_UI_SCRIM;
public HintState(int id) {
- super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
+ this(id, LAUNCHER_STATE_HOME);
+ }
+
+ public HintState(int id, int statsLogOrdinal) {
+ super(id, statsLogOrdinal, STATE_FLAGS);
}
@Override
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index cd74390..8e7dcc0 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -27,32 +27,21 @@
*/
public class StateAnimationConfig {
- // We separate the state animations into "atomic" and "non-atomic" components. The atomic
- // components may be run atomically - that is, all at once, instead of user-controlled. However,
- // atomic components are not restricted to this purpose; they can be user-controlled alongside
- // non atomic components as well. Note that each gesture model has exactly one atomic component,
- // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
@IntDef(flag = true, value = {
- PLAY_NON_ATOMIC,
- PLAY_ATOMIC_OVERVIEW_SCALE,
- PLAY_ATOMIC_OVERVIEW_PEEK,
+ SKIP_ALL_ANIMATIONS,
SKIP_OVERVIEW,
SKIP_DEPTH_CONTROLLER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationFlags {}
- public static final int PLAY_NON_ATOMIC = 1 << 0;
- public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
- public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
- public static final int SKIP_OVERVIEW = 1 << 3;
- public static final int SKIP_DEPTH_CONTROLLER = 1 << 4;
+ public static final int SKIP_ALL_ANIMATIONS = 1 << 0;
+ public static final int SKIP_OVERVIEW = 1 << 1;
+ public static final int SKIP_DEPTH_CONTROLLER = 1 << 2;
public long duration;
public boolean userControlled;
- public @AnimationFlags int animFlags = ANIM_ALL_COMPONENTS;
+ public @AnimationFlags int animFlags = 0;
- public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
- | PLAY_ATOMIC_OVERVIEW_PEEK;
// Various types of animation state transition
@IntDef(value = {
@@ -127,37 +116,9 @@
}
/**
- * @return Whether Overview is scaling as part of this animation. If this is the only
- * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
- * atomically, rather than being part of a normal state animation. StateHandlers can use
- * this to designate part of their animation that should scale with Overview.
- */
- public boolean playAtomicOverviewScaleComponent() {
- return hasAnimationFlag(StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE);
- }
-
- /**
- * @return Whether this animation will play atomically at the same time as a different,
- * user-controlled state transition. StateHandlers, which contribute to both animations, can
- * use this to avoid animating the same properties in both animations, since they'd conflict
- * with one another.
- */
- public boolean onlyPlayAtomicComponent() {
- return getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE
- || getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
- }
-
- /**
* Returns true if the config and any of the provided component flags
*/
public boolean hasAnimationFlag(@AnimationFlags int a) {
return (animFlags & a) != 0;
}
-
- /**
- * @return Only the flags that determine which animation components to play.
- */
- public @AnimationFlags int getAnimComponents() {
- return animFlags & StateAnimationConfig.ANIM_ALL_COMPONENTS;
- }
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index f34bff6..943d129 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -32,7 +32,8 @@
public static final int ALL_APPS_STATE_ORDINAL = 5;
public static final int BACKGROUND_APP_STATE_ORDINAL = 6;
public static final int HINT_STATE_ORDINAL = 7;
- public static final int OVERVIEW_SPLIT_SELECT_ORDINAL = 8;
+ public static final int HINT_STATE_TWO_BUTTON_ORDINAL = 8;
+ public static final int OVERVIEW_SPLIT_SELECT_ORDINAL = 9;
public static final String TAPL_EVENTS_TAG = "TaplEvents";
public static final String SEQUENCE_MAIN = "Main";
public static final String SEQUENCE_TIS = "TIS";
@@ -56,6 +57,8 @@
return "Background";
case HINT_STATE_ORDINAL:
return "Hint";
+ case HINT_STATE_TWO_BUTTON_ORDINAL:
+ return "Hint2Button";
case OVERVIEW_SPLIT_SELECT_ORDINAL:
return "OverviewSplitSelect";
default:
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 516fc74..a437293 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -27,30 +27,20 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_NON_ATOMIC;
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
-import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.os.SystemClock;
-import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
@@ -60,13 +50,6 @@
public abstract class AbstractStateChangeTouchController
implements TouchController, SingleAxisSwipeDetector.Listener {
- /**
- * Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
- * TODO: Remove the atomic animation altogether and just go to OVERVIEW directly (b/175137718).
- */
- public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 1f;
- protected final long ATOMIC_DURATION = getAtomicDuration();
-
protected final Launcher mLauncher;
protected final SingleAxisSwipeDetector mDetector;
protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
@@ -89,23 +72,7 @@
private float mProgressMultiplier;
private float mDisplacementShift;
private boolean mCanBlockFling;
- private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
-
- protected AnimatorSet mAtomicAnim;
- // True if we want to resume playing atomic components when mAtomicAnim completes.
- private boolean mScheduleResumeAtomicComponent;
- private AutoPlayAtomicAnimationInfo mAtomicAnimAutoPlayInfo;
-
- private boolean mPassedOverviewAtomicThreshold;
- // mAtomicAnim plays the atomic components of the state animations when we pass the threshold.
- // However, if we reinit to transition to a new state (e.g. OVERVIEW -> ALL_APPS) before the
- // atomic animation finishes, we only control the non-atomic components so that we don't
- // interfere with the atomic animation. When the atomic animation ends, we start controlling
- // the atomic components as well, using this controller.
- private AnimatorPlaybackController mAtomicComponentsController;
- private LauncherState mAtomicComponentsTargetState = NORMAL;
-
- private float mAtomicComponentsStartProgress;
+ private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
public AbstractStateChangeTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
mLauncher = l;
@@ -113,10 +80,6 @@
mSwipeDirection = dir;
}
- protected long getAtomicDuration() {
- return 200;
- }
-
protected abstract boolean canInterceptTouch(MotionEvent ev);
@Override
@@ -182,7 +145,7 @@
protected abstract LauncherState getTargetState(LauncherState fromState,
boolean isDragTowardPositive);
- protected abstract float initCurrentAnimation(@AnimationFlags int animComponents);
+ protected abstract float initCurrentAnimation();
private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState()
@@ -199,28 +162,10 @@
mToState = newToState;
mStartProgress = 0;
- mPassedOverviewAtomicThreshold = false;
if (mCurrentAnimation != null) {
mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
}
- int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
- ? PLAY_NON_ATOMIC : ANIM_ALL_COMPONENTS;
- mScheduleResumeAtomicComponent = false;
- if (mAtomicAnim != null) {
- animComponents = PLAY_NON_ATOMIC;
- // Control the non-atomic components until the atomic animation finishes, then control
- // the atomic components as well.
- mScheduleResumeAtomicComponent = true;
- }
- if (goingBetweenNormalAndOverview(mFromState, mToState)
- || mAtomicComponentsTargetState != mToState) {
- cancelAtomicComponentsController();
- }
-
- if (mAtomicComponentsController != null) {
- animComponents &= ~PLAY_ATOMIC_OVERVIEW_SCALE;
- }
- mProgressMultiplier = initCurrentAnimation(animComponents);
+ mProgressMultiplier = initCurrentAnimation();
mCurrentAnimation.dispatchOnStart();
return true;
}
@@ -231,13 +176,6 @@
protected void onReachedFinalState(LauncherState newToState) {
}
- protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
- LauncherState toState) {
- return (fromState == NORMAL || fromState == OVERVIEW)
- && (toState == NORMAL || toState == OVERVIEW)
- && mGoingBetweenStates;
- }
-
@Override
public void onDragStart(boolean start, float startDisplacement) {
mStartState = mLauncher.getStateManager().getState();
@@ -252,11 +190,6 @@
} else {
mCurrentAnimation.pause();
mStartProgress = mCurrentAnimation.getProgressFraction();
-
- mAtomicAnimAutoPlayInfo = null;
- if (mAtomicComponentsController != null) {
- mAtomicComponentsController.pause();
- }
}
mCanBlockFling = mFromState == NORMAL;
mFlingBlockCheck.unblockFling();
@@ -310,69 +243,6 @@
return;
}
mCurrentAnimation.setPlayFraction(fraction);
- if (mAtomicComponentsController != null) {
- // Make sure we don't divide by 0, and have at least a small runway.
- float start = Math.min(mAtomicComponentsStartProgress, 0.9f);
- mAtomicComponentsController.setPlayFraction((fraction - start) / (1 - start));
- }
- maybeUpdateAtomicAnim(mFromState, mToState, fraction);
- }
-
- /**
- * When going between normal and overview states, see if we passed the overview threshold and
- * play the appropriate atomic animation if so.
- */
- private void maybeUpdateAtomicAnim(LauncherState fromState, LauncherState toState,
- float progress) {
- if (!goingBetweenNormalAndOverview(fromState, toState)) {
- return;
- }
- boolean passedThreshold = progress >= ATOMIC_OVERVIEW_ANIM_THRESHOLD;
- if (passedThreshold != mPassedOverviewAtomicThreshold) {
- LauncherState atomicFromState = passedThreshold ? fromState: toState;
- LauncherState atomicToState = passedThreshold ? toState : fromState;
- mPassedOverviewAtomicThreshold = passedThreshold;
- if (mAtomicAnim != null) {
- mAtomicAnim.cancel();
- }
- mAtomicAnim = createAtomicAnimForState(atomicFromState, atomicToState, ATOMIC_DURATION);
- mAtomicAnim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mAtomicAnim = null;
- mScheduleResumeAtomicComponent = false;
- }
-
- @Override
- public void onAnimationSuccess(Animator animator) {
- if (!mScheduleResumeAtomicComponent) {
- return;
- }
- cancelAtomicComponentsController();
-
- if (mCurrentAnimation != null) {
- mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
- long duration = (long) (getShiftRange() * 2);
- mAtomicComponentsController = AnimatorPlaybackController.wrap(
- createAtomicAnimForState(mFromState, mToState, duration), duration);
- mAtomicComponentsController.dispatchOnStart();
- mAtomicComponentsTargetState = mToState;
- maybeAutoPlayAtomicComponentsAnim();
- }
- }
- });
- mAtomicAnim.start();
- mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
- }
- }
-
- private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
- long duration) {
- StateAnimationConfig config = getConfigForStates(fromState, targetState);
- config.animFlags = PLAY_ATOMIC_OVERVIEW_SCALE;
- config.duration = duration;
- return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, config);
}
/**
@@ -447,63 +317,18 @@
Math.min(progress, 1) - endProgress) * durationMultiplier;
}
}
-
+ if (targetState != mStartState) {
+ logReachedState(targetState);
+ }
mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState));
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
anim.setFloatValues(startProgress, endProgress);
- maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f);
- updateSwipeCompleteAnimation(anim, Math.max(duration, getRemainingAtomicDuration()),
- targetState, velocity, fling);
+ updateSwipeCompleteAnimation(anim, duration, targetState, velocity, fling);
mCurrentAnimation.dispatchOnStart();
if (fling && targetState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) {
mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
}
anim.start();
- mAtomicAnimAutoPlayInfo = new AutoPlayAtomicAnimationInfo(endProgress, anim.getDuration());
- maybeAutoPlayAtomicComponentsAnim();
- }
-
- /**
- * Animates the atomic components from the current progress to the final progress.
- *
- * Note that this only applies when we are controlling the atomic components separately from
- * the non-atomic components, which only happens if we reinit before the atomic animation
- * finishes.
- */
- private void maybeAutoPlayAtomicComponentsAnim() {
- if (mAtomicComponentsController == null || mAtomicAnimAutoPlayInfo == null) {
- return;
- }
-
- final AnimatorPlaybackController controller = mAtomicComponentsController;
- ValueAnimator atomicAnim = controller.getAnimationPlayer();
- atomicAnim.setFloatValues(controller.getProgressFraction(),
- mAtomicAnimAutoPlayInfo.toProgress);
- long duration = mAtomicAnimAutoPlayInfo.endTime - SystemClock.elapsedRealtime();
- mAtomicAnimAutoPlayInfo = null;
- if (duration <= 0) {
- atomicAnim.start();
- atomicAnim.end();
- mAtomicComponentsController = null;
- } else {
- atomicAnim.setDuration(duration);
- atomicAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mAtomicComponentsController == controller) {
- mAtomicComponentsController = null;
- }
- }
- });
- atomicAnim.start();
- }
- }
-
- private long getRemainingAtomicDuration() {
- if (mAtomicAnim == null) {
- return 0;
- }
- return mAtomicAnim.getTotalDuration() - mAtomicAnim.getCurrentPlayTime();
}
protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
@@ -513,10 +338,6 @@
}
protected void onSwipeInteractionCompleted(LauncherState targetState) {
- if (mAtomicComponentsController != null) {
- mAtomicComponentsController.getAnimationPlayer().end();
- mAtomicComponentsController = null;
- }
onReachedFinalState(mToState);
clearState();
boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
@@ -526,9 +347,6 @@
}
protected void goToTargetState(LauncherState targetState) {
- if (targetState != mStartState) {
- logReachedState(targetState);
- }
if (!mLauncher.isInState(targetState)) {
// If we're already in the target state, don't jump to it at the end of the animation in
// case the user started interacting with it before the animation finished.
@@ -556,37 +374,12 @@
protected void clearState() {
cancelAnimationControllers();
- if (mAtomicAnim != null) {
- mAtomicAnim.cancel();
- mAtomicAnim = null;
- }
mGoingBetweenStates = true;
- mScheduleResumeAtomicComponent = false;
mDetector.finishedScrolling();
mDetector.setDetectableScrollConditions(0, false);
}
private void cancelAnimationControllers() {
mCurrentAnimation = null;
- cancelAtomicComponentsController();
- }
-
- private void cancelAtomicComponentsController() {
- if (mAtomicComponentsController != null) {
- mAtomicComponentsController.getAnimationPlayer().cancel();
- mAtomicComponentsController = null;
- }
- mAtomicAnimAutoPlayInfo = null;
- }
-
- private static class AutoPlayAtomicAnimationInfo {
-
- public final float toProgress;
- public final long endTime;
-
- AutoPlayAtomicAnimationInfo(float toProgress, long duration) {
- this.toProgress = toProgress;
- this.endTime = duration + SystemClock.elapsedRealtime();
- }
}
}
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index f9dcf2d..ab2652a 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -23,24 +23,18 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
/**
* TouchController to switch between NORMAL and ALL_APPS state.
*/
public class AllAppsSwipeController extends AbstractStateChangeTouchController {
- private MotionEvent mTouchDownEvent;
-
public AllAppsSwipeController(Launcher l) {
super(l, SingleAxisSwipeDetector.VERTICAL);
}
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mTouchDownEvent = ev;
- }
if (mCurrentAnimation != null) {
// If we are already animating from a previous state, we can intercept.
return true;
@@ -69,11 +63,11 @@
}
@Override
- protected float initCurrentAnimation(@AnimationFlags int animComponents) {
+ protected float initCurrentAnimation() {
float range = getShiftRange();
long maxAccuracy = (long) (2 * range);
mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, maxAccuracy, animComponents);
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
float totalShift = endVerticalShift - startVerticalShift;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 19dfe15..dd5611e 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_SIDE;
import android.content.res.Resources;
import android.graphics.PointF;
@@ -45,7 +44,7 @@
import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class LandscapePagedViewHandler implements PagedOrientationHandler {
@@ -308,15 +307,10 @@
@Override
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- List<SplitPositionOption> options = new ArrayList<>(2);
- // Add left/right options where left => position top, right => position bottom
- options.add(new SplitPositionOption(
+ // Add "left" side of phone which is actually the top
+ return Collections.singletonList(new SplitPositionOption(
R.drawable.ic_split_screen, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
- return options;
}
@Override
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 29be627..2ca0340 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -306,16 +306,17 @@
@Override
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- List<SplitPositionOption> options = new ArrayList<>(2);
+ List<SplitPositionOption> options = new ArrayList<>(1);
// TODO: Add in correct icons
- if (dp.isLandscape) { // or seascape
+ if (dp.isSeascape()) { // or seascape
// Add left/right options
options.add(new SplitPositionOption(
+ R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
+ } else if (dp.isLandscape) {
+ options.add(new SplitPositionOption(
R.drawable.ic_split_screen, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
} else {
// Only add top option
options.add(new SplitPositionOption(
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index b5252f7..bd6e31b 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_SIDE;
import android.content.res.Resources;
import android.graphics.PointF;
@@ -33,7 +32,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@@ -96,15 +95,10 @@
@Override
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- List<SplitPositionOption> options = new ArrayList<>(2);
- // Add left/right options where left => position bottom, right => position top
- options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
- options.add(new SplitPositionOption(
+ // Add "right" option which is actually the top
+ return Collections.singletonList(new SplitPositionOption(
R.drawable.ic_split_screen, R.string.split_screen_position_right,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- return options;
}
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
diff --git a/src/com/android/launcher3/util/SettingsCache.java b/src/com/android/launcher3/util/SettingsCache.java
index 22b4d38..10611c7 100644
--- a/src/com/android/launcher3/util/SettingsCache.java
+++ b/src/com/android/launcher3/util/SettingsCache.java
@@ -39,12 +39,11 @@
* {@link #unregister(Uri, OnChangeListener)} methods.
*
* This can be used as a normal cache without any listeners as well via the
- * {@link #getValue(Uri, int)} and {@link #dispatchOnChange(Uri)} to update (and subsequently call
+ * {@link #getValue(Uri, int)} and {@link #onChange)} to update (and subsequently call
* get)
*
* The cache will be invalidated/updated through the normal
* {@link ContentObserver#onChange(boolean)} calls
- * or can be force updated by calling {@link #dispatchOnChange(Uri)}.
*
* Cache will also be updated if a key queried is missing (even if it has no listeners registered).
*/
@@ -58,9 +57,6 @@
/** Hidden field Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED */
public static final String ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED =
"swipe_bottom_to_notification_enabled";
- /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
- public static final Uri NOTIFICATION_ENABLED_LISTENERS =
- Settings.Secure.getUriFor("enabled_notification_listeners");
public static final Uri ROTATION_SETTING_URI =
Settings.System.getUriFor(ACCELEROMETER_ROTATION);
@@ -103,6 +99,14 @@
* Returns the value for this classes key from the cache. If not in cache, will call
* {@link #updateValue(Uri, int)} to fetch.
*/
+ public boolean getValue(Uri keySetting) {
+ return getValue(keySetting, 1);
+ }
+
+ /**
+ * Returns the value for this classes key from the cache. If not in cache, will call
+ * {@link #updateValue(Uri, int)} to fetch.
+ */
public boolean getValue(Uri keySetting, int defaultValue) {
if (mKeyCache.containsKey(keySetting)) {
return mKeyCache.get(keySetting);
@@ -140,14 +144,6 @@
}
/**
- * Force update a change for a given URI and have all listeners for that URI receive callbacks
- * even if the value is unchanged.
- */
- public void dispatchOnChange(Uri uri) {
- onChange(true, uri);
- }
-
- /**
* Call to stop receiving updates on the given {@param listener}.
* This Uri/Listener pair must correspond to the same pair called with for
* {@link #register(Uri, OnChangeListener)}
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 512a286..e8a0635 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -28,6 +28,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
/**
@@ -92,10 +93,7 @@
}
public static int getAttrColor(Context context, int attr) {
- TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
- int colorAccent = ta.getColor(0, 0);
- ta.recycle();
- return colorAccent;
+ return GraphicsUtils.getAttrColor(context, attr);
}
public static boolean getAttrBoolean(Context context, int attr) {
@@ -120,23 +118,6 @@
}
/**
- * Returns the alpha corresponding to the theme attribute {@param attr}, in the range [0, 255].
- */
- public static int getAlpha(Context context, int attr) {
- return (int) (255 * getFloat(context, attr, 0) + 0.5f);
- }
-
- /**
- * Returns the alpha corresponding to the theme attribute {@param attr}
- */
- public static float getFloat(Context context, int attr, float defValue) {
- TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
- float value = ta.getFloat(0, defValue);
- ta.recycle();
- return value;
- }
-
- /**
* Scales a color matrix such that, when applied to color R G B A, it produces R' G' B' A' where
* R' = r * R
* G' = g * G
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index e08f881..f79313f 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -216,7 +216,7 @@
return mLauncher.getDragLayer();
}
- protected static View createColorScrim(Context context, int bgColor) {
+ protected View createColorScrim(Context context, int bgColor) {
View view = new View(context);
view.forceHasOverlappingRendering(false);
view.setBackgroundColor(bgColor);
diff --git a/src/com/android/launcher3/views/AccessibilityActionsView.java b/src/com/android/launcher3/views/AccessibilityActionsView.java
index 0eacaa3..1d136c3 100644
--- a/src/com/android/launcher3/views/AccessibilityActionsView.java
+++ b/src/com/android/launcher3/views/AccessibilityActionsView.java
@@ -67,7 +67,7 @@
info.addAction(new AccessibilityAction(
R.string.all_apps_button_label, l.getText(R.string.all_apps_button_label)));
for (OptionItem item : OptionsPopupView.getOptions(l)) {
- info.addAction(new AccessibilityAction(item.labelRes, l.getText(item.labelRes)));
+ info.addAction(new AccessibilityAction(item.labelRes, item.label));
}
return info;
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 9a2db10..98cc876 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
@@ -37,6 +38,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.core.content.ContextCompat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
@@ -62,6 +64,7 @@
private final ArrayMap<View, OptionItem> mItemMap = new ArrayMap<>();
private RectF mTargetRect;
+ private boolean mShouldAddArrow;
public OptionsPopupView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -113,9 +116,13 @@
return (type & TYPE_OPTIONS_POPUP) != 0;
}
+ public void setShouldAddArrow(boolean shouldAddArrow) {
+ mShouldAddArrow = shouldAddArrow;
+ }
+
@Override
protected boolean shouldAddArrow() {
- return false;
+ return mShouldAddArrow;
}
@Override
@@ -124,16 +131,17 @@
}
public static OptionsPopupView show(
- Launcher launcher, RectF targetRect, List<OptionItem> items) {
+ Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow) {
OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
.inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
popup.mTargetRect = targetRect;
+ popup.setShouldAddArrow(shouldAddArrow);
for (OptionItem item : items) {
DeepShortcutView view =
(DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup);
- view.getIconView().setBackgroundResource(item.iconRes);
- view.getBubbleText().setText(item.labelRes);
+ view.getIconView().setBackgroundDrawable(item.icon);
+ view.getBubbleText().setText(item.label);
view.setOnClickListener(popup);
view.setOnLongClickListener(popup);
popup.mItemMap.put(view, item);
@@ -154,7 +162,7 @@
y = launcher.getDragLayer().getHeight() / 2;
}
RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
- show(launcher, target, getOptions(launcher));
+ show(launcher, target, getOptions(launcher), false);
}
/**
@@ -162,11 +170,15 @@
*/
public static ArrayList<OptionItem> getOptions(Launcher launcher) {
ArrayList<OptionItem> options = new ArrayList<>();
- options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
+ options.add(new OptionItem(launcher,
+ R.string.settings_button_text,
+ R.drawable.ic_setting,
LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
OptionsPopupView::startSettings));
if (!WidgetsModel.GO_DISABLE_WIDGETS) {
- options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+ options.add(new OptionItem(launcher,
+ R.string.widget_button_text,
+ R.drawable.ic_widget,
LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
OptionsPopupView::onWidgetsClicked));
}
@@ -174,7 +186,9 @@
R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
R.drawable.ic_palette : R.drawable.ic_wallpaper;
- options.add(new OptionItem(resString, resDrawable,
+ options.add(new OptionItem(launcher,
+ resString,
+ resDrawable,
IGNORE,
OptionsPopupView::startWallpaperPicker));
return options;
@@ -241,15 +255,28 @@
public static class OptionItem {
+ // Used to create AccessibilityNodeInfo in AccessibilityActionsView.java.
public final int labelRes;
- public final int iconRes;
+
+ public final CharSequence label;
+ public final Drawable icon;
public final EventEnum eventId;
public final OnLongClickListener clickListener;
- public OptionItem(int labelRes, int iconRes, EventEnum eventId,
- OnLongClickListener clickListener) {
+ public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId,
+ OnLongClickListener clickListener) {
this.labelRes = labelRes;
- this.iconRes = iconRes;
+ this.label = context.getText(labelRes);
+ this.icon = ContextCompat.getDrawable(context, iconRes);
+ this.eventId = eventId;
+ this.clickListener = clickListener;
+ }
+
+ public OptionItem(CharSequence label, Drawable icon, EventEnum eventId,
+ OnLongClickListener clickListener) {
+ this.labelRes = 0;
+ this.label = label;
+ this.icon = icon;
this.eventId = eventId;
this.clickListener = clickListener;
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 7f0765b..72926dd 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -40,6 +40,7 @@
* Simple scrim which draws a flat color
*/
public class ScrimView<T extends Launcher> extends View implements Insettable, OnChangeListener {
+ private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = .1f;
protected final T mLauncher;
private final WallpaperColorInfo mWallpaperColorInfo;
@@ -117,7 +118,7 @@
protected void updateSysUiColors() {
// Use a light system UI (dark icons) if all apps is behind at least half of the
// status bar.
- boolean forceChange = mProgress <= 0.1f;
+ boolean forceChange = mProgress <= STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
if (forceChange) {
mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
} else {
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index d0ec9d7..9701389 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -15,51 +15,25 @@
*/
package com.android.launcher3.views;
-import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
-import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
-import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
-
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
-import android.util.SparseBooleanArray;
-import android.view.View;
import android.widget.EdgeEffect;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
-import androidx.dynamicanimation.animation.DynamicAnimation;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory;
+import com.android.launcher3.Utilities;
+
+/**
+ * View group to allow rendering overscroll effect in a child at the parent level
+ */
public class SpringRelativeLayout extends RelativeLayout {
- private static final float STIFFNESS = (STIFFNESS_MEDIUM + STIFFNESS_LOW) / 2;
- private static final float DAMPING_RATIO = DAMPING_RATIO_MEDIUM_BOUNCY;
- private static final float VELOCITY_MULTIPLIER = 0.3f;
-
- private static final FloatPropertyCompat<SpringRelativeLayout> DAMPED_SCROLL =
- new FloatPropertyCompat<SpringRelativeLayout>("value") {
-
- @Override
- public float getValue(SpringRelativeLayout object) {
- return object.mDampedScrollShift;
- }
-
- @Override
- public void setValue(SpringRelativeLayout object, float value) {
- object.setDampedScrollShift(value);
- }
- };
-
- protected final SparseBooleanArray mSpringViews = new SparseBooleanArray();
- private final SpringAnimation mSpring;
-
- private float mDampedScrollShift = 0;
- private SpringEdgeEffect mActiveEdge;
+ private final EdgeEffect mEdgeGlowTop;
+ private final EdgeEffect mEdgeGlowBottom;
public SpringRelativeLayout(Context context) {
this(context, null);
@@ -71,98 +45,73 @@
public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mSpring = new SpringAnimation(this, DAMPED_SCROLL, 0);
- mSpring.setSpring(new SpringForce(0)
- .setStiffness(STIFFNESS)
- .setDampingRatio(DAMPING_RATIO));
- }
-
- public void addSpringView(int id) {
- mSpringViews.put(id, true);
- }
-
- public void removeSpringView(int id) {
- mSpringViews.delete(id);
- invalidate();
- }
-
- /**
- * Used to clip the canvas when drawing child views during overscroll.
- */
- public int getCanvasClipTopForOverscroll() {
- return 0;
+ mEdgeGlowTop = Utilities.ATLEAST_S
+ ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
+ mEdgeGlowBottom = Utilities.ATLEAST_S
+ ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
+ setWillNotDraw(false);
}
@Override
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- if (mDampedScrollShift != 0 && mSpringViews.get(child.getId())) {
- int saveCount = canvas.save();
-
- canvas.clipRect(0, getCanvasClipTopForOverscroll(), getWidth(), getHeight());
- canvas.translate(0, mDampedScrollShift);
- boolean result = super.drawChild(canvas, child, drawingTime);
-
- canvas.restoreToCount(saveCount);
-
- return result;
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (!mEdgeGlowTop.isFinished()) {
+ final int restoreCount = canvas.save();
+ canvas.translate(0, 0);
+ mEdgeGlowTop.setSize(getWidth(), getHeight());
+ if (mEdgeGlowTop.draw(canvas)) {
+ postInvalidateOnAnimation();
+ }
+ canvas.restoreToCount(restoreCount);
}
- return super.drawChild(canvas, child, drawingTime);
- }
-
- private void setActiveEdge(SpringEdgeEffect edge) {
- if (mActiveEdge != edge && mActiveEdge != null) {
- mActiveEdge.mDistance = 0;
- }
- mActiveEdge = edge;
- }
-
- protected void setDampedScrollShift(float shift) {
- if (shift != mDampedScrollShift) {
- mDampedScrollShift = shift;
- invalidate();
+ if (!mEdgeGlowBottom.isFinished()) {
+ final int restoreCount = canvas.save();
+ final int width = getWidth();
+ final int height = getHeight();
+ canvas.translate(-width, height);
+ canvas.rotate(180, width, 0);
+ mEdgeGlowBottom.setSize(width, height);
+ if (mEdgeGlowBottom.draw(canvas)) {
+ postInvalidateOnAnimation();
+ }
+ canvas.restoreToCount(restoreCount);
}
}
- private void finishScrollWithVelocity(float velocity) {
- mSpring.setStartVelocity(velocity);
- mSpring.setStartValue(mDampedScrollShift);
- mSpring.start();
- }
- protected void finishWithShiftAndVelocity(float shift, float velocity,
- DynamicAnimation.OnAnimationEndListener listener) {
- setDampedScrollShift(shift);
- mSpring.addEndListener(listener);
- finishScrollWithVelocity(velocity);
+ /**
+ * Absorbs the velocity as a result for swipe-up fling
+ */
+ protected void absorbSwipeUpVelocity(int velocity) {
+ mEdgeGlowBottom.onAbsorb(velocity);
+ invalidate();
}
public EdgeEffectFactory createEdgeEffectFactory() {
- return new SpringEdgeEffectFactory();
+ return new ProxyEdgeEffectFactory();
}
- private class SpringEdgeEffectFactory extends EdgeEffectFactory {
+ private class ProxyEdgeEffectFactory extends EdgeEffectFactory {
@NonNull @Override
protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
switch (direction) {
case DIRECTION_TOP:
- return new SpringEdgeEffect(getContext(), +VELOCITY_MULTIPLIER);
+ return new EdgeEffectProxy(getContext(), mEdgeGlowTop);
case DIRECTION_BOTTOM:
- return new SpringEdgeEffect(getContext(), -VELOCITY_MULTIPLIER);
+ return new EdgeEffectProxy(getContext(), mEdgeGlowBottom);
}
return super.createEdgeEffect(view, direction);
}
}
- private class SpringEdgeEffect extends EdgeEffect {
+ private class EdgeEffectProxy extends EdgeEffect {
- private final float mVelocityMultiplier;
+ private final EdgeEffect mParent;
- private float mDistance;
-
- public SpringEdgeEffect(Context context, float velocityMultiplier) {
+ EdgeEffectProxy(Context context, EdgeEffect parent) {
super(context);
- mVelocityMultiplier = velocityMultiplier;
+ mParent = parent;
}
@Override
@@ -170,22 +119,44 @@
return false;
}
+ private void invalidateParentScrollEffect() {
+ if (!mParent.isFinished()) {
+ invalidate();
+ }
+ }
+
@Override
public void onAbsorb(int velocity) {
- finishScrollWithVelocity(velocity * mVelocityMultiplier);
+ mParent.onAbsorb(velocity);
+ invalidateParentScrollEffect();
+ }
+
+ @Override
+ public void onPull(float deltaDistance) {
+ mParent.onPull(deltaDistance);
+ invalidateParentScrollEffect();
}
@Override
public void onPull(float deltaDistance, float displacement) {
- setActiveEdge(this);
- mDistance += deltaDistance * (mVelocityMultiplier / 3f);
- setDampedScrollShift(mDistance * getHeight());
+ mParent.onPull(deltaDistance, displacement);
+ invalidateParentScrollEffect();
}
@Override
public void onRelease() {
- mDistance = 0;
- finishScrollWithVelocity(0);
+ mParent.onRelease();
+ invalidateParentScrollEffect();
+ }
+
+ @Override
+ public void finish() {
+ mParent.finish();
+ }
+
+ @Override
+ public boolean isFinished() {
+ return mParent.isFinished();
}
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 4b113d8..3308eec 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -16,7 +16,6 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import android.content.Context;
@@ -37,8 +36,8 @@
import android.widget.RemoteViews;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -152,12 +151,12 @@
// 2) Preload icon in the center
// 3) Setup icon in the center and app icon in the top right corner.
if (mDisabledForSafeMode) {
- FastBitmapDrawable disabledIcon = newIcon(getContext(), info);
+ FastBitmapDrawable disabledIcon = info.newIcon(getContext());
disabledIcon.setIsDisabled(true);
mCenterDrawable = disabledIcon;
mSettingIconDrawable = null;
} else if (isReadyForClickSetup()) {
- mCenterDrawable = newIcon(getContext(), info);
+ mCenterDrawable = info.newIcon(getContext());
mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
updateSettingColor(info.bitmap.color);
} else {
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 08bb662..3e61e56 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -29,7 +29,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.PendingAddItemInfo;
@@ -38,7 +37,9 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
/**
@@ -118,12 +119,12 @@
.addDragListener(new AppWidgetHostViewDragListener(launcher));
}
if (preview == null) {
- FastBitmapDrawable p = new FastBitmapDrawable(
+ Drawable p = new FastBitmapDrawable(
app.getWidgetCache().generateWidgetPreview(launcher,
createWidgetInfo.info, maxWidth, null,
previewSizeBeforeScale).first);
if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
- p.setRoundedCornersRadius(mEnforcedRoundedCornersForWidget);
+ p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
}
preview = p;
}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 2b4b9ea..40b256b 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -40,12 +40,13 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.dragndrop.AppWidgetHostViewDrawable;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.model.WidgetItem;
/**
@@ -248,8 +249,7 @@
public void applyPreview(Bitmap bitmap) {
FastBitmapDrawable drawable = new FastBitmapDrawable(bitmap);
- drawable.setRoundedCornersRadius(mEnforcedCornerRadius);
- applyPreview(drawable);
+ applyPreview(new RoundDrawableWrapper(drawable, mEnforcedCornerRadius));
}
private void applyPreview(Drawable drawable) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 29c00b2..a4257a2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -144,17 +144,12 @@
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> mViewPager.snapToPage(1));
fastScroller.setIsRecyclerViewFirstChildInParent(false);
- springLayout.addSpringView(R.id.primary_widgets_list_view);
- springLayout.addSpringView(R.id.work_widgets_list_view);
} else {
mViewPager = null;
- springLayout.addSpringView(R.id.primary_widgets_list_view);
}
layoutInflater.inflate(R.layout.widgets_full_sheet_search_and_recommendations, springLayout,
true);
- springLayout.addSpringView(R.id.search_and_recommendations_container);
-
mSearchAndRecommendationViewHolder = new SearchAndRecommendationViewHolder(
findViewById(R.id.search_and_recommendations_container));
mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController(
@@ -174,7 +169,7 @@
onWidgetsBound();
mSearchAndRecommendationViewHolder.mSearchBar.initialize(
- mLauncher.getPopupDataProvider().getAllWidgets(), /* searchModeListener= */ this);
+ mLauncher.getPopupDataProvider(), /* searchModeListener= */ this);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 75dd409..497c72e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.widget.picker;
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
-
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -32,11 +30,11 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.icons.PlaceHolderIconDrawable;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
@@ -145,7 +143,7 @@
}
private void setIcon(PackageItemInfo info) {
- FastBitmapDrawable icon = newIcon(getContext(), info);
+ FastBitmapDrawable icon = info.newIcon(getContext());
applyDrawables(icon);
mIconDrawable = icon;
if (mIconDrawable != null) {
diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
index 56a08b1..42f1bb2 100644
--- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
@@ -26,10 +26,7 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.R;
-import com.android.launcher3.search.SearchAlgorithm;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
/**
* View for a search bar with an edit text with a cancel button.
@@ -54,12 +51,10 @@
}
@Override
- public void initialize(List<WidgetsListBaseEntry> allWidgets,
- SearchModeListener searchModeListener) {
- SearchAlgorithm<WidgetsListBaseEntry> algo =
- new SimpleWidgetsSearchAlgorithm(new SimpleWidgetsSearchPipeline(allWidgets));
+ public void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener) {
mController = new WidgetsSearchBarController(
- algo, mEditText, mCancelButton, searchModeListener);
+ new SimpleWidgetsSearchAlgorithm(dataProvider),
+ mEditText, mCancelButton, searchModeListener);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 15d2454..9be3b5f 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -16,42 +16,41 @@
package com.android.launcher3.widget.picker.search;
-import android.os.Handler;
-import android.util.Log;
+import static com.android.launcher3.search.StringMatcherUtility.matches;
+import android.os.Handler;
+
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
+import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* Implementation of {@link SearchAlgorithm} that posts a task to query on the main thread.
*/
public final class SimpleWidgetsSearchAlgorithm implements SearchAlgorithm<WidgetsListBaseEntry> {
- private static final boolean DEBUG = false;
- private static final String TAG = "SimpleWidgetsSearchAlgo";
- private static final String DELIM = "\t";
-
private final Handler mResultHandler;
- private final WidgetsPickerSearchPipeline mSearchPipeline;
+ private final PopupDataProvider mDataProvider;
- public SimpleWidgetsSearchAlgorithm(WidgetsPickerSearchPipeline searchPipeline) {
+ public SimpleWidgetsSearchAlgorithm(PopupDataProvider dataProvider) {
mResultHandler = new Handler();
- mSearchPipeline = searchPipeline;
+ mDataProvider = dataProvider;
}
@Override
public void doSearch(String query, SearchCallback<WidgetsListBaseEntry> callback) {
- long startTime = System.currentTimeMillis();
- String queryToken = query + DELIM + startTime;
- if (DEBUG) {
- Log.d(TAG, "doSearch queryToken:" + queryToken);
- }
- mSearchPipeline.query(query,
- results -> mResultHandler.post(
- () -> callback.onSearchResult(queryToken, new ArrayList(results))));
+ ArrayList<WidgetsListBaseEntry> result = getFilteredWidgets(mDataProvider, query);
+ mResultHandler.post(() -> callback.onSearchResult(query, result));
}
@Override
@@ -60,4 +59,36 @@
mResultHandler.removeCallbacksAndMessages(/*token= */null);
}
}
+
+ /**
+ * Returns entries for all matched widgets
+ */
+ public static ArrayList<WidgetsListBaseEntry> getFilteredWidgets(
+ PopupDataProvider dataProvider, String input) {
+ ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
+ dataProvider.getAllWidgets().stream()
+ .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+ .forEach(headerEntry -> {
+ List<WidgetItem> matchedWidgetItems = filterWidgetItems(
+ input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
+ if (matchedWidgetItems.size() > 0) {
+ results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+ headerEntry.mTitleSectionName, matchedWidgetItems));
+ results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
+ headerEntry.mTitleSectionName, matchedWidgetItems));
+ }
+ });
+ return results;
+ }
+
+ private static List<WidgetItem> filterWidgetItems(String query, String packageTitle,
+ List<WidgetItem> items) {
+ StringMatcher matcher = StringMatcher.getInstance();
+ if (matches(query, packageTitle, matcher)) {
+ return items;
+ }
+ return items.stream()
+ .filter(item -> matches(query, item.label, matcher))
+ .collect(Collectors.toList());
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
deleted file mode 100644
index 5222e8e..0000000
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker.search;
-
-import static com.android.launcher3.search.StringMatcherUtility.matches;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-/**
- * Implementation of {@link WidgetsPickerSearchPipeline} that performs search by prefix matching on
- * app names and widget labels.
- */
-public final class SimpleWidgetsSearchPipeline implements WidgetsPickerSearchPipeline {
-
- private final List<WidgetsListBaseEntry> mAllEntries;
-
- public SimpleWidgetsSearchPipeline(List<WidgetsListBaseEntry> allEntries) {
- mAllEntries = allEntries;
- }
-
- @Override
- public void query(String input, Consumer<List<WidgetsListBaseEntry>> callback) {
- ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
- mAllEntries.stream().filter(entry -> entry instanceof WidgetsListHeaderEntry)
- .forEach(headerEntry -> {
- List<WidgetItem> matchedWidgetItems = filterWidgetItems(
- input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
- if (matchedWidgetItems.size() > 0) {
- results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
- headerEntry.mTitleSectionName, matchedWidgetItems));
- results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
- headerEntry.mTitleSectionName, matchedWidgetItems));
- }
- });
- callback.accept(results);
- }
-
- private List<WidgetItem> filterWidgetItems(String query, String packageTitle,
- List<WidgetItem> items) {
- StringMatcher matcher = StringMatcher.getInstance();
- if (matches(query, packageTitle, matcher)) {
- return items;
- }
- return items.stream()
- .filter(item -> matches(query, item.label, matcher))
- .collect(Collectors.toList());
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
deleted file mode 100644
index d12782c..0000000
--- a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker.search;
-
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * An interface for a pipeline to handle widgets search.
- */
-public interface WidgetsPickerSearchPipeline {
-
- /**
- * Performs a search query asynchronically. Invokes {@code callback} when the search is
- * complete.
- */
- void query(String input, Consumer<List<WidgetsListBaseEntry>> callback);
-
- /**
- * Cancels any ongoing search request.
- */
- default void cancel() {};
-
- /**
- * Cleans up after search is no longer needed.
- */
- default void destroy() {};
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
index 3ac82c0..0ac47ce 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
@@ -16,9 +16,7 @@
package com.android.launcher3.widget.picker.search;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
/**
* Interface for a widgets picker search bar.
@@ -27,7 +25,7 @@
/**
* Attaches a controller to the search bar which interacts with {@code searchModeListener}.
*/
- void initialize(List<WidgetsListBaseEntry> allWidgets, SearchModeListener searchModeListener);
+ void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener);
/**
* Clears search bar.
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 0edfbed..d4e8f1f 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -503,6 +503,7 @@
// Destroy Launcher activity.
executeOnLauncher(launcher -> {
if (launcher != null) {
+ onLauncherActivityClose(launcher);
launcher.finish();
}
});
@@ -511,7 +512,7 @@
}
protected boolean isInBackground(Launcher launcher) {
- return !launcher.hasBeenResumed();
+ return launcher == null || !launcher.hasBeenResumed();
}
protected boolean isInState(Supplier<LauncherState> state) {
@@ -524,7 +525,7 @@
return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
}
- private static void checkLauncherIntegrity(
+ private void checkLauncherIntegrity(
Launcher launcher, ContainerType expectedContainerType) {
if (launcher != null) {
final StateManager<LauncherState> stateManager = launcher.getStateManager();
@@ -535,10 +536,8 @@
stableState == stateManager.getState());
final boolean isResumed = launcher.hasBeenResumed();
- assertTrue("hasBeenResumed() != isStarted(), hasBeenResumed(): " + isResumed,
- isResumed == launcher.isStarted());
- assertTrue("hasBeenResumed() != isUserActive(), hasBeenResumed(): " + isResumed,
- isResumed == launcher.isUserActive());
+ final boolean isStarted = launcher.isStarted();
+ checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
final int ordinal = stableState.ordinal;
@@ -561,8 +560,7 @@
break;
}
case OVERVIEW: {
- assertTrue(
- "Launcher is not resumed in state: " + expectedContainerType,
+ checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
isResumed);
assertTrue(TestProtocol.stateOrdinalToString(ordinal),
ordinal == TestProtocol.OVERVIEW_STATE_ORDINAL);
@@ -587,4 +585,20 @@
expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
}
}
+
+ protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
+ boolean isResumed, boolean isStarted) {
+ assertTrue("hasBeenResumed() != isStarted(), hasBeenResumed(): " + isResumed,
+ isResumed == isStarted);
+ assertTrue("hasBeenResumed() != isUserActive(), hasBeenResumed(): " + isResumed,
+ isResumed == launcher.isUserActive());
+ }
+
+ protected void checkLauncherStateInOverview(Launcher launcher,
+ ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
+ assertTrue("Launcher is not resumed in state: " + expectedContainerType,
+ isResumed);
+ }
+
+ protected void onLauncherActivityClose(Launcher launcher) { }
}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src_disabled/WorkTabTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/ui/WorkTabTest.java
rename to tests/src_disabled/WorkTabTest.java
index 8f4381b..bfacc74 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src_disabled/WorkTabTest.java
@@ -42,6 +42,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -90,6 +91,7 @@
});
}
+ @Ignore("b/182844465")
@Test
public void workTabExists() {
mDevice.pressHome();
@@ -102,6 +104,7 @@
launcher -> launcher.getAppsView().isWorkTabVisible(), 60000);
}
+ @Ignore("b/182844465")
@Test
public void toggleWorks() {
mDevice.pressHome();
@@ -133,6 +136,7 @@
l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile));
}
+ @Ignore("b/182844465")
@Test
public void testWorkEduFlow() {
mDevice.pressHome();
@@ -176,6 +180,7 @@
});
}
+ @Ignore("b/182844465")
@Test
public void testWorkEduIntermittent() {
mDevice.pressHome();
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index d317783..4a666b1 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -122,7 +122,9 @@
endY = startY - swipeLength;
} else {
startX = getSwipeStartX();
- endX = startX - swipeLength;
+ // TODO(b/184059820) make horizontal swipe use swipe width not height, for the
+ // moment just double the swipe length.
+ endX = startX - swipeLength * 2;
startY = endY = mLauncher.getDevice().getDisplayHeight() / 2;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7bfe33c..475a4ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -52,6 +52,7 @@
import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
@@ -867,6 +868,16 @@
return object;
}
+ @Nullable
+ UiObject2 findObjectInContainer(UiObject2 container, BySelector selector) {
+ try {
+ return container.findObject(selector);
+ } catch (StaleObjectException e) {
+ fail("The container disappeared from screen");
+ return null;
+ }
+ }
+
@NonNull
List<UiObject2> getObjectsInContainer(UiObject2 container, String resName) {
try {
@@ -1059,6 +1070,11 @@
final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer;
final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop();
+ scrollDownByDistance(container, distance);
+ }
+
+ void scrollDownByDistance(UiObject2 container, int distance) {
+ final Rect containerRect = getVisibleBounds(container);
final int bottomGestureMarginInContainer = getBottomGestureMarginInContainer(container);
scroll(
container,
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index f084913..a3f9ade 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -17,6 +17,7 @@
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
+import static com.android.launcher3.tapl.LauncherInstrumentation.log;
import android.graphics.Rect;
@@ -29,13 +30,13 @@
import com.android.launcher3.testing.TestProtocol;
import java.util.Collection;
-import java.util.List;
/**
* All widgets container.
*/
public final class Widgets extends LauncherInstrumentation.VisibleContainer {
private static final int FLING_STEPS = 10;
+ private static final int SCROLL_ATTEMPTS = 60;
Widgets(LauncherInstrumentation launcher) {
super(launcher);
@@ -49,7 +50,7 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to fling forward in widgets")) {
- LauncherInstrumentation.log("Widgets.flingForward enter");
+ log("Widgets.flingForward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
mLauncher.scroll(
widgetsContainer,
@@ -60,7 +61,7 @@
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
verifyActiveContainer();
}
- LauncherInstrumentation.log("Widgets.flingForward exit");
+ log("Widgets.flingForward exit");
}
}
@@ -71,7 +72,7 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to fling backwards in widgets")) {
- LauncherInstrumentation.log("Widgets.flingBackward enter");
+ log("Widgets.flingBackward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
mLauncher.scroll(
widgetsContainer,
@@ -81,7 +82,7 @@
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
}
- LauncherInstrumentation.log("Widgets.flingBackward exit");
+ log("Widgets.flingBackward exit");
}
}
@@ -101,11 +102,12 @@
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"getting widget " + labelText + " in widgets list")) {
final UiObject2 searchBar = findSearchBar();
+ final int searchBarHeight = searchBar.getVisibleBounds().height();
final UiObject2 fullWidgetsPicker = verifyActiveContainer();
mLauncher.assertTrue("Widgets container didn't become scrollable",
fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
- final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer(searchBar);
+ final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer();
mLauncher.assertTrue("Can't locate widgets list for the test app: "
+ mLauncher.getLauncherPackageName(),
widgetsContainer != null);
@@ -118,7 +120,8 @@
for (UiObject2 row : tableRows) {
final Collection<UiObject2> widgetCells = row.getChildren();
for (UiObject2 widget : widgetCells) {
- final UiObject2 label = widget.findObject(labelSelector);
+ final UiObject2 label = mLauncher.findObjectInContainer(widget,
+ labelSelector);
if (label == null) {
continue;
}
@@ -126,28 +129,15 @@
"View is not WidgetCell",
"com.android.launcher3.widget.WidgetCell",
widget.getClassName());
- UiObject2 preview = widget.findObject(previewSelector);
- mLauncher.assertTrue("Can't find widget preview", preview != null);
- Rect previewRect = new Rect(preview.getVisibleBounds());
- boolean intersected = searchBar.getVisibleBounds().intersect(previewRect);
- if (intersected) {
- Rect scrollUp = new Rect(/* left= */ 0, /* top= */0, /* right*/ 0,
- /* bottom= */ searchBar.getVisibleBounds().height());
- mLauncher.scroll(
- fullWidgetsPicker,
- Direction.UP,
- scrollUp,
- /* steps= */ 2,
- /* slowDown= */ true);
- }
- preview = widget.findObject(previewSelector);
+ UiObject2 preview = mLauncher.waitForObjectInContainer(widget,
+ previewSelector);
return new Widget(mLauncher, preview);
}
}
- mLauncher.assertTrue("Too many attempts", ++i <= 40);
+ mLauncher.assertTrue("Too many attempts", ++i <= SCROLL_ATTEMPTS);
final int scroll = getWidgetsScroll();
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, tableRows, 0);
+ mLauncher.scrollDownByDistance(fullWidgetsPicker, searchBarHeight);
final int newScroll = getWidgetsScroll();
mLauncher.assertTrue(
"Scrolled in a wrong direction in Widgets: from " + scroll + " to "
@@ -164,14 +154,13 @@
"widgets_search_bar");
final UiObject2 searchBarContainer = mLauncher.waitForLauncherObject(
searchBarContainerSelector);
- mLauncher.assertTrue("Can't find a search bar container", searchBarContainer != null);
- UiObject2 searchBar = searchBarContainer.findObject(searchBarSelector);
- mLauncher.assertTrue("Can't find a search bar", searchBar != null);
+ UiObject2 searchBar = mLauncher.waitForObjectInContainer(searchBarContainer,
+ searchBarSelector);
return searchBar;
}
/** Finds the widgets list of this test app from the collapsed full widgets picker. */
- private UiObject2 findTestAppWidgetsTableContainer(final UiObject2 searchBar) {
+ private UiObject2 findTestAppWidgetsTableContainer() {
final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_list_header");
final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
@@ -180,50 +169,34 @@
"widgets_table");
boolean hasHeaderExpanded = false;
- for (int i = 0; i < 40; i++) {
+ for (int i = 0; i < SCROLL_ATTEMPTS; i++) {
UiObject2 fullWidgetsPicker = verifyActiveContainer();
- UiObject2 header = fullWidgetsPicker.findObject(headerSelector);
- mLauncher.assertTrue("Can't find a widget header", header != null);
+ UiObject2 header = mLauncher.waitForObjectInContainer(fullWidgetsPicker,
+ headerSelector);
+ int headerHeight = header.getVisibleBounds().height();
// Look for a header that has the test app name.
- UiObject2 headerTitle = fullWidgetsPicker.findObject(targetAppSelector);
+ UiObject2 headerTitle = mLauncher.findObjectInContainer(fullWidgetsPicker,
+ targetAppSelector);
if (headerTitle != null) {
- Rect headerTitleRect = new Rect(headerTitle.getVisibleBounds());
- boolean intersected = searchBar.getVisibleBounds().intersect(headerTitleRect);
- if (intersected) {
- Rect scrollUp = new Rect(/* left= */ 0, /* top= */0, /* right*/ 0,
- /* bottom= */ searchBar.getVisibleBounds().height());
- mLauncher.scroll(
- fullWidgetsPicker,
- Direction.UP,
- scrollUp,
- /* steps= */ 2,
- /* slowDown= */ true);
- }
// If we find the header and it has not been expanded, let's click it to see the
// widgets list.
if (!hasHeaderExpanded) {
+ log("Header has not been expanded. Click to expand.");
hasHeaderExpanded = true;
mLauncher.clickLauncherObject(headerTitle);
- // After clicking the header, the recyclerview has been updated. Let's refresh
- // the container UIObject2.
- fullWidgetsPicker = verifyActiveContainer();
- // Refresh headerTitle because the first instance is stale after
- // verifyActiveContainer call.
- headerTitle = fullWidgetsPicker.findObject(targetAppSelector);
}
// Look for a widgets list.
- UiObject2 widgetsContainer = fullWidgetsPicker.findObject(widgetsContainerSelector);
+ UiObject2 widgetsContainer = mLauncher.findObjectInContainer(fullWidgetsPicker,
+ widgetsContainerSelector);
if (widgetsContainer != null) {
+ log("Widgets container found.");
return widgetsContainer;
}
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, List.of(headerTitle), 0);
- } else {
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, fullWidgetsPicker.getChildren(),
- 0);
}
+ mLauncher.scrollDownByDistance(fullWidgetsPicker, headerHeight);
}
return null;