Merge "Detect force visible nav bar based on kids mode." into tm-qpr-dev
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index a1566f0..f5a277b 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -22,6 +22,7 @@
// Wrapper message for containers used at the quickstep level.
// Message name should match with launcher_atom_extension.proto message at
// the AOSP level.
+// Next ID = 3
message ExtendedContainers {
reserved 2; // Deleted fields
@@ -31,10 +32,16 @@
}
// Represents on-device search result container.
+// Next ID = 4
message DeviceSearchResultContainer{
optional int32 query_length = 1;
optional SearchAttributes search_attributes = 2;
+ // [0, m], m varies based on the display density and resolution
+ // To indicate the location of the tapped on-device search result.
+ // For application, it will be the column number in the apps row.
+ optional int32 grid_x = 3;
+ // Next ID = 4
message SearchAttributes{
// True if results are based on spell corrected query
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 3a0adc9..643b1d5 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -89,7 +89,7 @@
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"क्या आपको नेविगेशन ट्यूटोरियल छोड़ना है?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"इसे बाद में <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर देखा जा सकता है"</string>
- <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"अभी नहीं"</string>
+ <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द करें"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"छोड़ें"</string>
<string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन घुमाएं"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार ट्यूटोरियल दिखाया गया"</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index e1a3b72..b20752d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -31,7 +31,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.mapBoundToRange;
-import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
@@ -184,6 +183,10 @@
public static final int SPLIT_DIVIDER_ANIM_DURATION = 100;
public static final int CONTENT_ALPHA_DURATION = 217;
+ public static final int TASKBAR_TO_APP_DURATION = 600;
+ // TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
+ // is solved.
+ public static final int TASKBAR_TO_HOME_DURATION = 300;
protected static final int CONTENT_SCALE_DURATION = 350;
protected static final int CONTENT_SCRIM_DURATION = 350;
@@ -527,7 +530,15 @@
workspace.forEachVisiblePage(
view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
- viewsToAnimate.add(mLauncher.getHotseat());
+ // Do not scale hotseat as a whole when taskbar is present, and scale QSB only if it's
+ // not inline.
+ if (mDeviceProfile.isTaskbarPresent) {
+ if (!mDeviceProfile.isQsbInline) {
+ viewsToAnimate.add(mLauncher.getHotseat().getQsb());
+ }
+ } else {
+ viewsToAnimate.add(mLauncher.getHotseat());
+ }
viewsToAnimate.forEach(view -> {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index ca30e72..6df31e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -171,7 +171,9 @@
isResumed,
fromInit,
/* startAnimation= */ true,
- QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
+ !isResumed
+ ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
+ : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
}
@Nullable
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 5d576f7..01cf23b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -35,6 +35,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
import android.animation.ArgbEvaluator;
@@ -105,6 +106,7 @@
private static final int FLAG_DISABLE_BACK = 1 << 9;
private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 11;
+ private static final int FLAG_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 12;
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
@@ -207,9 +209,12 @@
boolean isInKidsMode = mContext.isNavBarKidsModeActive();
boolean alwaysShowButtons = isThreeButtonNav || isInSetup;
- // Make sure to remove nav bar buttons translation when notification shade is expanded or
- // IME is showing (add separate translation for IME).
- int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE;
+ // Make sure to remove nav bar buttons translation when any of the following occur:
+ // - Notification shade is expanded
+ // - IME is showing (add separate translation for IME)
+ // - VoiceInteractionWindow (assistant) is showing
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
+ | FLAG_VOICE_INTERACTION_WINDOW_SHOWING;
mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
1, 0));
@@ -443,6 +448,8 @@
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+ boolean isVoiceInteractionWindowShowing =
+ (sysUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0;
// TODO(b/202218289) we're getting IME as not visible on lockscreen from system
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
@@ -453,6 +460,7 @@
updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive);
+ updateStateForFlag(FLAG_VOICE_INTERACTION_WINDOW_SHOWING, isVoiceInteractionWindowShowing);
if (mA11yButton != null) {
// Only used in 3 button
@@ -750,6 +758,8 @@
appendFlag(str, flags, FLAG_NOTIFICATION_SHADE_EXPANDED,
"FLAG_NOTIFICATION_SHADE_EXPANDED");
appendFlag(str, flags, FLAG_SCREEN_PINNING_ACTIVE, "FLAG_SCREEN_PINNING_ACTIVE");
+ appendFlag(str, flags, FLAG_VOICE_INTERACTION_WINDOW_SHOWING,
+ "FLAG_VOICE_INTERACTION_WINDOW_SHOWING");
return str.toString();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index b797807..f472427 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -43,7 +43,8 @@
public static final int ALPHA_INDEX_STASHED = 0;
public static final int ALPHA_INDEX_HOME_DISABLED = 1;
- private static final int NUM_ALPHA_CHANNELS = 2;
+ public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2;
+ private static final int NUM_ALPHA_CHANNELS = 3;
/**
* The SharedPreferences key for whether the stashed handle region is dark.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index dc2e3b6..d1994e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -200,7 +201,8 @@
new TaskbarPopupController(this),
new TaskbarForceVisibleImmersiveController(this),
new TaskbarAllAppsController(this, dp),
- new TaskbarInsetsController(this));
+ new TaskbarInsetsController(this),
+ new VoiceInteractionWindowController(this));
}
public void init(@NonNull TaskbarSharedState sharedState) {
@@ -246,12 +248,20 @@
return super.getStatsLogManager();
}
- /** Creates LayoutParams for adding a view directly to WindowManager as a new window */
+ /** @see #createDefaultWindowLayoutParams(int) */
public WindowManager.LayoutParams createDefaultWindowLayoutParams() {
+ return createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL);
+ }
+
+ /**
+ * Creates LayoutParams for adding a view directly to WindowManager as a new window.
+ * @param type The window type to pass to the created WindowManager.LayoutParams.
+ */
+ public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) {
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
MATCH_PARENT,
mLastRequestedNonFullscreenHeight,
- TYPE_NAVIGATION_BAR_PANEL,
+ type,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
@@ -468,6 +478,8 @@
fromInit);
mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
+ mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
+ (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
}
/**
@@ -612,7 +624,9 @@
/** Removes the given view from WindowManager. See {@link #addWindowView}. */
public void removeWindowView(View view) {
- mWindowManager.removeViewImmediate(view);
+ if (view.isAttachedToWindow()) {
+ mWindowManager.removeViewImmediate(view);
+ }
}
protected void onTaskbarIconClicked(View view) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 449e0a7..d7b50b0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -52,6 +52,7 @@
public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController;
public final TaskbarAllAppsController taskbarAllAppsController;
public final TaskbarInsetsController taskbarInsetsController;
+ public final VoiceInteractionWindowController voiceInteractionWindowController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@@ -80,7 +81,8 @@
TaskbarPopupController taskbarPopupController,
TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController,
TaskbarAllAppsController taskbarAllAppsController,
- TaskbarInsetsController taskbarInsetsController) {
+ TaskbarInsetsController taskbarInsetsController,
+ VoiceInteractionWindowController voiceInteractionWindowController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -99,6 +101,7 @@
this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController;
this.taskbarAllAppsController = taskbarAllAppsController;
this.taskbarInsetsController = taskbarInsetsController;
+ this.voiceInteractionWindowController = voiceInteractionWindowController;
}
/**
@@ -126,13 +129,15 @@
taskbarAllAppsController.init(this, sharedState.allAppsVisible);
navButtonController.init(this);
taskbarInsetsController.init(this);
+ voiceInteractionWindowController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
taskbarDragLayerController, taskbarScrimViewController, taskbarViewController,
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController, taskbarEduController,
- taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController
+ taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
+ voiceInteractionWindowController
};
mAreAllControllersInitialized = true;
@@ -172,6 +177,7 @@
taskbarAllAppsController.onDestroy();
navButtonController.onDestroy();
taskbarInsetsController.onDestroy();
+ voiceInteractionWindowController.onDestroy();
mControllersToLog = null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 6a6a693..e4f82d2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,6 +18,7 @@
import android.graphics.Insets
import android.graphics.Region
import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
+import android.view.InsetsState
import android.view.WindowManager
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
@@ -61,9 +62,6 @@
)
)
- windowLayoutParams.providedInternalInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
- windowLayoutParams.providedInternalImeInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
-
onTaskbarWindowHeightOrInsetsChanged()
windowLayoutParams.insetsRoundedCornerFrame = true
@@ -75,32 +73,23 @@
}
fun onTaskbarWindowHeightOrInsetsChanged() {
- var reducingSize = getReducingInsetsForTaskbarInsetsHeight(
- controllers.taskbarStashController.contentHeightToReportToApps)
+ var contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
+ contentRegion.set(0, windowLayoutParams.height - contentHeight,
+ context.deviceProfile.widthPx, windowLayoutParams.height)
+ var tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ for (provider in windowLayoutParams.providedInsets) {
+ if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR) {
+ provider.insetsSize = Insets.of(0, 0, 0, contentHeight)
+ } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT
+ || provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) {
+ provider.insetsSize = Insets.of(0, 0, 0, tappableHeight)
+ }
+ }
- contentRegion.set(0, reducingSize.top,
- context.deviceProfile.widthPx, windowLayoutParams.height)
- windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
- windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize
- reducingSize = getReducingInsetsForTaskbarInsetsHeight(
- controllers.taskbarStashController.tappableHeightToReportToApps)
- windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
- windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize
-
- reducingSize = getReducingInsetsForTaskbarInsetsHeight(taskbarHeightForIme)
- windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
- windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
- windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize
- }
-
- /**
- * WindowLayoutParams.providedInternal*Insets expects Insets that subtract from the window frame
- * height (i.e. WindowLayoutParams#height). So for Taskbar to report bottom insets to apps, it
- * actually provides insets from the top of its window frame.
- * @param height The number of pixels from the bottom of the screen that Taskbar insets.
- */
- private fun getReducingInsetsForTaskbarInsetsHeight(height: Int): Insets {
- return Insets.of(0, windowLayoutParams.height - height, 0, 0)
+ var imeInsetsSize = Insets.of(0, 0, 0, taskbarHeightForIme)
+ for (provider in windowLayoutParams.providedInsets) {
+ provider.imeInsetsSize = imeInsetsSize
+ }
}
/**
@@ -151,13 +140,10 @@
override fun dumpLogs(prefix: String, pw: PrintWriter) {
pw.println(prefix + "TaskbarInsetsController:")
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
- pw.println("$prefix\tprovidedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
- "${windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
- pw.println("$prefix\tprovidedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
- "${windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}")
- pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
- "${windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
- pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
- "${windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}")
+ for (provider in windowLayoutParams.providedInsets) {
+ pw.println("$prefix\tprovidedInsets: (type=" + InsetsState.typeToString(provider.type)
+ + " insetsSize=" + provider.insetsSize
+ + " imeInsetsSize=" + provider.imeInsetsSize + ")")
+ }
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index dc0ef27..591b32f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -19,11 +19,13 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -31,6 +33,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.MultiValueAlpha;
@@ -44,7 +47,6 @@
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.StringJoiner;
-import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -53,6 +55,9 @@
*/
public class TaskbarLauncherStateController {
+ private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
public static final int FLAG_RESUMED = 1 << 0;
public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2;
@@ -99,7 +104,11 @@
}
updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
if (!mShouldDelayLauncherStateAnim) {
- applyState();
+ if (toState == LauncherState.NORMAL) {
+ applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
+ } else {
+ applyState();
+ }
}
}
@@ -122,7 +131,12 @@
MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
mIconAlphaForHome.setConsumer(
- (Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
+ alpha -> {
+ mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1);
+ if (mLauncher.getDeviceProfile().isQsbInline) {
+ mLauncher.getHotseat().setQsbAlpha(alpha > 0 ? 0 : 1);
+ }
+ });
mIconAlignmentForResumedState.finishAnimation();
onIconAlignmentRatioChangedForAppAndHomeTransition();
@@ -269,6 +283,11 @@
ObjectAnimator resumeAlignAnim = mIconAlignmentForResumedState
.animateToValue(toAlignmentForResumedState)
.setDuration(duration);
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForResumedState - "
+ + mIconAlignmentForResumedState.value
+ + " -> " + toAlignmentForResumedState + ": " + duration);
+ }
resumeAlignAnim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -305,6 +324,11 @@
if (isRecentsAnimationRunning) {
gestureAlignAnim.setDuration(duration);
}
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForGestureState - "
+ + mIconAlignmentForGestureState.value
+ + " -> " + toAlignmentForGestureState + ": " + duration);
+ }
gestureAlignAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -330,6 +354,7 @@
.setDuration(duration));
}
+ animatorSet.setInterpolator(EMPHASIZED);
if (start) {
animatorSet.start();
}
@@ -374,6 +399,12 @@
mIconAlignmentForLauncherState.finishAnimation();
animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
.setDuration(duration));
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForLauncherState - "
+ + mIconAlignmentForLauncherState.value
+ + " -> " + toAlignment + ": " + duration);
+ }
+ animatorSet.setInterpolator(EMPHASIZED);
}
}
@@ -396,17 +427,17 @@
onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome);
}
- private void onIconAlignmentRatioChanged(Supplier<Float> alignmentSupplier) {
+ private void onIconAlignmentRatioChanged(Supplier<AnimatedFloat> alignmentSupplier) {
if (mControllers == null) {
return;
}
- float alignment = alignmentSupplier.get();
+ AnimatedFloat animatedFloat = alignmentSupplier.get();
float currentValue = mIconAlphaForHome.getValue();
- boolean taskbarWillBeVisible = alignment < 1;
+ boolean taskbarWillBeVisible = animatedFloat.value < 1;
boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0)
|| (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
- updateIconAlignment(alignment);
+ updateIconAlignment(animatedFloat.value, animatedFloat.getEndValue());
// Sync the first frame where we swap taskbar and hotseat.
if (firstFrameVisChanged && mCanSyncViews && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
@@ -416,21 +447,22 @@
}
}
- private void updateIconAlignment(float alignment) {
+ private void updateIconAlignment(float alignment, Float endAlignment) {
mControllers.taskbarViewController.setLauncherIconAlignment(
- alignment, mLauncher.getDeviceProfile());
+ alignment, endAlignment, mLauncher.getDeviceProfile());
// Switch taskbar and hotseat in last frame
setTaskbarViewVisible(alignment < 1);
mControllers.navbarButtonsViewController.updateTaskbarAlignment(alignment);
}
- private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
- return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ private AnimatedFloat getCurrentIconAlignmentRatioBetweenAppAndHome() {
+ return mIconAlignmentForResumedState.value > mIconAlignmentForGestureState.value
+ ? mIconAlignmentForResumedState : mIconAlignmentForGestureState;
}
- private float getCurrentIconAlignmentRatioForLauncherState() {
- return mIconAlignmentForLauncherState.value;
+ private AnimatedFloat getCurrentIconAlignmentRatioForLauncherState() {
+ return mIconAlignmentForLauncherState;
}
private void setTaskbarViewVisible(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 6f88d64..6a43cc5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +32,7 @@
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -78,6 +80,8 @@
// Only non-null when device supports having an All Apps button.
private @Nullable AllAppsButton mAllAppsButton;
+ private View mQsb;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -117,6 +121,9 @@
new ViewGroup.LayoutParams(mIconTouchSize, mIconTouchSize));
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
}
+
+ // TODO: Disable touch events on QSB otherwise it can crash.
+ mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
}
private int getColorWithGivenLuminance(int color, float luminance) {
@@ -166,6 +173,7 @@
if (mAllAppsButton != null) {
removeView(mAllAppsButton);
}
+ removeView(mQsb);
for (int i = 0; i < hotseatItemInfos.length; i++) {
ItemInfo hotseatItemInfo = hotseatItemInfos[i];
@@ -242,6 +250,11 @@
int index = Utilities.isRtl(getResources()) ? 0 : getChildCount();
addView(mAllAppsButton, index);
}
+ if (mActivityContext.getDeviceProfile().isQsbInline) {
+ addView(mQsb, Utilities.isRtl(getResources()) ? getChildCount() : 0);
+ // Always set QSB to invisible after re-adding.
+ mQsb.setVisibility(View.INVISIBLE);
+ }
mThemeIconsBackground = calculateThemeIconsBackground();
setThemedIconsBackgroundColor(mThemeIconsBackground);
@@ -273,7 +286,12 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int count = getChildCount();
- int spaceNeeded = count * (mItemMarginLeftRight * 2 + mIconTouchSize);
+ int countExcludingQsb = count;
+ DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+ if (deviceProfile.isQsbInline) {
+ countExcludingQsb--;
+ }
+ int spaceNeeded = countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
int navSpaceNeeded = ApiWrapper.getHotseatEndOffset(getContext());
boolean layoutRtl = isLayoutRtl();
int iconEnd = right - (right - left - spaceNeeded) / 2;
@@ -292,10 +310,25 @@
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
for (int i = count; i > 0; i--) {
View child = getChildAt(i - 1);
- iconEnd -= mItemMarginLeftRight;
- int iconStart = iconEnd - mIconTouchSize;
- child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
- iconEnd = iconStart - mItemMarginLeftRight;
+ if (child == mQsb) {
+ int qsbStart;
+ int qsbEnd;
+ if (layoutRtl) {
+ qsbStart = iconEnd + mItemMarginLeftRight;
+ qsbEnd = qsbStart + deviceProfile.qsbWidth;
+ } else {
+ qsbEnd = iconEnd - mItemMarginLeftRight;
+ qsbStart = qsbEnd - deviceProfile.qsbWidth;
+ }
+ int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
+ int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
+ child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
+ } else {
+ iconEnd -= mItemMarginLeftRight;
+ int iconStart = iconEnd - mIconTouchSize;
+ child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
+ iconEnd = iconStart - mItemMarginLeftRight;
+ }
}
mIconLayoutBounds.left = iconEnd;
}
@@ -367,6 +400,13 @@
return mAllAppsButton;
}
+ /**
+ * Returns the QSB in the taskbar.
+ */
+ public View getQsb() {
+ return mQsb;
+ }
+
// FolderIconParent implemented methods.
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 3562f5b..0cbd0d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
@@ -35,12 +36,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.HorizontalInsettableView;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.MultiValueAlpha;
@@ -63,7 +67,8 @@
public static final int ALPHA_INDEX_STASH = 2;
public static final int ALPHA_INDEX_RECENTS_DISABLED = 3;
public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
- private static final int NUM_ALPHA_CHANNELS = 5;
+ public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5;
+ private static final int NUM_ALPHA_CHANNELS = 6;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
@@ -210,9 +215,10 @@
* 0 => not aligned
* 1 => fully aligned
*/
- public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
+ public void setLauncherIconAlignment(float alignmentRatio, Float endAlignment,
+ DeviceProfile launcherDp) {
if (mIconAlignControllerLazy == null) {
- mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+ mIconAlignControllerLazy = createIconAlignmentController(launcherDp, endAlignment);
}
mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
if (alignmentRatio <= 0 || alignmentRatio >= 1) {
@@ -224,11 +230,13 @@
/**
* Creates an animation for aligning the taskbar icons with the provided Launcher device profile
*/
- private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
+ private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp,
+ Float endAlignment) {
mOnControllerPreCreateCallback.run();
PendingAnimation setter = new PendingAnimation(100);
+ DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
- float scaleUp = ((float) launcherDp.iconSizePx) / mActivity.getDeviceProfile().iconSizePx;
+ float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.iconSizePx;
int borderSpacing = launcherDp.hotseatBorderSpace;
int hotseatCellSize = DeviceProfile.calculateCellWidth(
launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right,
@@ -245,14 +253,13 @@
}
int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight();
- int expandedHeight = Math.max(collapsedHeight,
- mActivity.getDeviceProfile().taskbarSize + offsetY);
+ int expandedHeight = Math.max(collapsedHeight, taskbarDp.taskbarSize + offsetY);
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+ boolean isToHome = endAlignment != null && endAlignment == 1;
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
-
int positionInHotseat;
if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
&& child == mTaskbarView.getAllAppsButtonView()) {
@@ -260,13 +267,46 @@
// as its convenient for animation purposes.
positionInHotseat = Utilities.isRtl(child.getResources())
? -1
- : mActivity.getDeviceProfile().numShownHotseatIcons;
+ : taskbarDp.numShownHotseatIcons;
if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
- setter.setViewAlpha(child, 0, LINEAR);
+ setter.setViewAlpha(child, 0,
+ isToHome
+ ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f)
+ : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f));
}
} else if (child.getTag() instanceof ItemInfo) {
positionInHotseat = ((ItemInfo) child.getTag()).screenId;
+ } else if (child == mTaskbarView.getQsb()) {
+ boolean isRtl = Utilities.isRtl(child.getResources());
+ float hotseatIconCenter = isRtl
+ ? launcherDp.widthPx - hotseatPadding.right + borderSpacing
+ + launcherDp.qsbWidth / 2f
+ : hotseatPadding.left - borderSpacing - launcherDp.qsbWidth / 2f;
+ float childCenter = (child.getLeft() + child.getRight()) / 2f;
+ float halfQsbIconWidthDiff = (launcherDp.qsbWidth - taskbarDp.iconSizePx) / 2f;
+ setter.addFloat(child, ICON_TRANSLATE_X,
+ isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff,
+ hotseatIconCenter - childCenter, LINEAR);
+
+ int qsbContentHeight = child.getHeight() - child.getPaddingTop()
+ - child.getPaddingBottom();
+ float scale = ((float) taskbarDp.iconSizePx) / qsbContentHeight;
+ setter.addFloat(child, SCALE_PROPERTY, scale, 1f, LINEAR);
+
+ setter.addFloat(child, VIEW_ALPHA, 0f, 1f,
+ isToHome
+ ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f)
+ : Interpolators.clampToProgress(LINEAR, 0.84f, 1f));
+ setter.addOnFrameListener(animator -> AlphaUpdateListener.updateVisibility(child));
+
+ float qsbInsetFraction = halfQsbIconWidthDiff / launcherDp.qsbWidth;
+ if (child instanceof HorizontalInsettableView) {
+ setter.addFloat((HorizontalInsettableView) child,
+ HorizontalInsettableView.HORIZONTAL_INSETS, qsbInsetFraction, 0,
+ LINEAR);
+ }
+ continue;
} else {
Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
continue;
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
new file mode 100644
index 0000000..946873e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -0,0 +1,109 @@
+package com.android.launcher3.taskbar
+
+import android.graphics.Canvas
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import com.android.launcher3.views.BaseDragLayer
+import com.android.systemui.animation.ViewRootSync
+import java.io.PrintWriter
+
+private const val TASKBAR_ICONS_FADE_DURATION = 300L
+private const val STASHED_HANDLE_FADE_DURATION = 180L
+
+/**
+ * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing.
+ */
+class VoiceInteractionWindowController(val context: TaskbarActivityContext)
+ : TaskbarControllers.LoggableTaskbarController {
+
+ private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
+
+ // Initialized in init.
+ private lateinit var controllers: TaskbarControllers
+ private lateinit var separateWindowForTaskbarBackground: BaseDragLayer<TaskbarActivityContext>
+ private lateinit var separateWindowLayoutParams: WindowManager.LayoutParams
+
+ private var isVoiceInteractionWindowVisible: Boolean = false
+
+ fun init(controllers: TaskbarControllers) {
+ this.controllers = controllers
+
+ separateWindowForTaskbarBackground =
+ object : BaseDragLayer<TaskbarActivityContext>(context, null, 0) {
+ override fun recreateControllers() {
+ mControllers = emptyArray()
+ }
+
+ override fun draw(canvas: Canvas) {
+ super.draw(canvas)
+ taskbarBackgroundRenderer.draw(canvas)
+ }
+ }
+ separateWindowForTaskbarBackground.recreateControllers()
+ separateWindowForTaskbarBackground.setWillNotDraw(false)
+
+ separateWindowLayoutParams = context.createDefaultWindowLayoutParams(
+ TYPE_APPLICATION_OVERLAY)
+ separateWindowLayoutParams.isSystemApplicationOverlay = true
+ }
+
+ fun onDestroy() {
+ setIsVoiceInteractionWindowVisible(visible = false, skipAnim = true)
+ }
+
+ fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
+ if (isVoiceInteractionWindowVisible == visible) {
+ return
+ }
+ isVoiceInteractionWindowVisible = visible
+
+ // Fade out taskbar icons and stashed handle.
+ val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
+ val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha
+ .getProperty(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+ .animateToValue(taskbarIconAlpha)
+ .setDuration(TASKBAR_ICONS_FADE_DURATION)
+ val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha
+ .getProperty(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+ .animateToValue(taskbarIconAlpha)
+ .setDuration(STASHED_HANDLE_FADE_DURATION)
+ fadeTaskbarIcons.start()
+ fadeStashedHandle.start()
+ if (skipAnim) {
+ fadeTaskbarIcons.end()
+ fadeStashedHandle.end()
+ }
+
+ if (context.isGestureNav && controllers.taskbarStashController.isInAppAndNotStashed) {
+ moveTaskbarBackgroundToLowerLayer()
+ }
+ }
+
+ /**
+ * Hides the TaskbarDragLayer background and creates a new window to draw just that background.
+ */
+ private fun moveTaskbarBackgroundToLowerLayer() {
+ val taskbarBackgroundOverride = controllers.taskbarDragLayerController
+ .overrideBackgroundAlpha
+ if (isVoiceInteractionWindowVisible) {
+ // First add the temporary window, then hide the overlapping taskbar background.
+ context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams)
+ ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer
+ ) {
+ taskbarBackgroundOverride.updateValue(0f)
+ }
+ } else {
+ // First reapply the original taskbar background, then remove the temporary window.
+ taskbarBackgroundOverride.updateValue(1f)
+ ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer
+ ) {
+ context.removeWindowView(separateWindowForTaskbarBackground)
+ }
+ }
+ }
+
+ override fun dumpLogs(prefix: String, pw: PrintWriter) {
+ pw.println(prefix + "VoiceInteractionWindowController:")
+ pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 6fd98db..61b038e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -171,8 +171,8 @@
* This method should be called after an exit animation finishes, if applicable.
*/
void maybeCloseWindow() {
- if (AbstractFloatingView.getOpenView(mAllAppsContext, TYPE_ALL) != null
- || mAllAppsContext.getDragController().isSystemDragInProgress()) {
+ if (mAllAppsContext != null && (AbstractFloatingView.hasOpenView(mAllAppsContext, TYPE_ALL)
+ || mAllAppsContext.getDragController().isSystemDragInProgress())) {
return;
}
mProxyView.close(false);
@@ -187,7 +187,7 @@
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
Optional.ofNullable(mAllAppsContext)
.map(c -> c.getSystemService(WindowManager.class))
- .ifPresent(m -> m.removeView(mAllAppsContext.getDragLayer()));
+ .ifPresent(m -> m.removeViewImmediate(mAllAppsContext.getDragLayer()));
mAllAppsContext = null;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 429f209..6427e09 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -131,9 +131,14 @@
@Override
public void onBackPressed(Launcher launcher) {
- TaskView taskView = launcher.<RecentsView>getOverviewPanel().getRunningTaskView();
+ RecentsView recentsView = launcher.getOverviewPanel();
+ TaskView taskView = recentsView.getRunningTaskView();
if (taskView != null) {
- taskView.launchTasks();
+ if (recentsView.isTaskViewFullyVisible(taskView)) {
+ taskView.launchTasks();
+ } else {
+ recentsView.snapToPage(recentsView.indexOfChild(taskView));
+ }
} else {
super.onBackPressed(launcher);
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 13272e9..b3e2d91 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -234,7 +234,6 @@
STATE_LAUNCHER_BIND_TO_SERVICE;
public static final long MAX_SWIPE_DURATION = 350;
- 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 =
@@ -1141,7 +1140,9 @@
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
- duration = HOME_DURATION;
+ duration = mActivity.getDeviceProfile().isTaskbarPresent
+ ? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
+ : StaggeredWorkspaceAnim.DURATION_MS;
// Early detach the nav bar once the endTarget is determined as HOME
if (mRecentsAnimationController != null) {
mRecentsAnimationController.detachNavigationBarFromApp(true);
@@ -1284,8 +1285,11 @@
? runningTaskTarget.taskInfo.launchCookies
: new ArrayList<>();
boolean isTranslucent = runningTaskTarget != null && runningTaskTarget.isTranslucent;
+ boolean hasValidLeash = runningTaskTarget != null
+ && runningTaskTarget.leash != null
+ && runningTaskTarget.leash.isValid();
boolean appCanEnterPip = !mDeviceState.isPipActive()
- && runningTaskTarget != null
+ && hasValidLeash
&& runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
@@ -1394,9 +1398,6 @@
}
}
- /**
- * TODO(b/195473090) handle multiple task simulators (if needed) for PIP
- */
private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
// Directly animate the app to PiP (picture-in-picture) mode
@@ -1676,7 +1677,7 @@
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
- if (mRecentsAnimationTargets != null) {
+ if (mRecentsAnimationTargets != null && wasVisible) {
setDividerShown(true /* shown */, true /* immediate */);
}
@@ -1799,6 +1800,7 @@
new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
+ tx.setShouldDisableCanAffectSystemUiFlags(false);
int[] taskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 6c7a885..a166553 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -133,4 +133,11 @@
public boolean isAnimatingToValue(float endValue) {
return isAnimating() && mEndValue != null && mEndValue == endValue;
}
+
+ /**
+ * Returns the value we are animating to, or {@code null} if we are not currently animating.
+ */
+ public Float getEndValue() {
+ return mEndValue;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index dffdc5a..1e7e89e 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -235,6 +235,10 @@
}
};
+ RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
+ if (visibleRecentsView != null) {
+ visibleRecentsView.moveFocusedTaskToFront();
+ }
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState);
cmd.mActiveCallbacks.addListener(interactionHandler);
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index d11d50b..1634c08 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -165,7 +165,7 @@
}
@Override
- public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
+ public boolean onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
mThumbnailCache.updateTaskSnapShot(taskId, snapshot);
for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) {
@@ -174,6 +174,7 @@
task.thumbnail = snapshot;
}
}
+ return true;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 6179b81..db402af 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -514,9 +514,6 @@
for (SurfaceControl leash: openingTargets) {
t.setAlpha(leash, progress);
}
- for (SurfaceControl leash: closingTargets) {
- t.setAlpha(leash, 1 - progress);
- }
t.apply();
});
animator.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 85ef6cb..45c8036 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -462,6 +462,7 @@
private LatencyType mType = LatencyType.UNKNOWN;
private int mPackageId = 0;
private long mLatencyInMillis;
+ private int mQueryLength = -1;
StatsCompatLatencyLogger(Context context, ActivityContext activityContext) {
mContext = context;
@@ -493,6 +494,12 @@
}
@Override
+ public StatsLatencyLogger withQueryLength(int queryLength) {
+ this.mQueryLength = queryLength;
+ return this;
+ }
+
+ @Override
public void log(EventEnum event) {
if (IS_VERBOSE) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
@@ -508,7 +515,8 @@
mInstanceId.getId(), // instance_id
mPackageId, // package_id
mLatencyInMillis, // latency_in_millis
- mType.getId() //type
+ mType.getId(), //type
+ mQueryLength // query_length
);
}
}
@@ -574,14 +582,18 @@
}
private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
- if (info.getContainerInfo().getContainerCase() == FOLDER) {
+ LauncherAtom.ContainerInfo containerInfo = info.getContainerInfo();
+ if (containerInfo.getContainerCase() == FOLDER) {
if (parent) {
- return info.getContainerInfo().getFolder().getWorkspace().getGridX();
+ return containerInfo.getFolder().getWorkspace().getGridX();
} else {
- return info.getContainerInfo().getFolder().getGridX();
+ return containerInfo.getFolder().getGridX();
}
+ } else if (containerInfo.getContainerCase() == EXTENDED_CONTAINERS) {
+ return containerInfo.getExtendedContainers()
+ .getDeviceSearchResultContainer().getGridX();
} else {
- return info.getContainerInfo().getWorkspace().getGridX();
+ return containerInfo.getWorkspace().getGridX();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 32e08ff..de527a7 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -41,6 +41,7 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
@@ -60,10 +61,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;
+ public static final int DURATION_TASKBAR_MS =
+ QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -91,16 +92,20 @@
mSpringTransY = transFactor * launcher.getResources()
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);
+ DeviceProfile grid = launcher.getDeviceProfile();
+ long duration = grid.isTaskbarPresent ? DURATION_TASKBAR_MS : DURATION_MS;
if (staggerWorkspace) {
- DeviceProfile grid = launcher.getDeviceProfile();
Workspace<?> workspace = launcher.getWorkspace();
Hotseat hotseat = launcher.getHotseat();
- // Hotseat and QSB takes up two additional rows.
- int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
+ boolean staggerHotseat = !grid.isVerticalBarLayout() && !grid.isTaskbarPresent;
+ boolean staggerQsb =
+ !grid.isVerticalBarLayout() && !(grid.isTaskbarPresent && grid.isQsbInline);
+ int totalRows = grid.inv.numRows + (staggerHotseat ? 1 : 0) + (staggerQsb ? 1 : 0);
// Add animation for all the visible workspace pages
- workspace.forEachVisiblePage(page -> addAnimationForPage((CellLayout) page, totalRows));
+ workspace.forEachVisiblePage(
+ page -> addAnimationForPage((CellLayout) page, totalRows, duration));
boolean workspaceClipChildren = workspace.getClipChildren();
boolean workspaceClipToPadding = workspace.getClipToPadding();
@@ -119,23 +124,34 @@
View child = hotseatIcons.getChildAt(i);
CellLayout.LayoutParams lp =
((CellLayout.LayoutParams) child.getLayoutParams());
- addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
+ addStaggeredAnimationForView(child, lp.cellY + 1, totalRows, duration);
}
} else {
final int hotseatRow, qsbRow;
if (grid.isTaskbarPresent) {
- qsbRow = grid.inv.numRows + 1;
- hotseatRow = grid.inv.numRows + 2;
+ if (grid.isQsbInline) {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 1;
+ } else {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 2;
+ }
} else {
hotseatRow = grid.inv.numRows + 1;
qsbRow = grid.inv.numRows + 2;
}
- for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatIcons.getChildAt(i);
- addStaggeredAnimationForView(child, hotseatRow, totalRows);
- }
- addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows);
+ // Do not stagger hotseat as a whole when taskbar is present, and stagger QSB only
+ // if it's not inline.
+ if (staggerHotseat) {
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
+ addStaggeredAnimationForView(child, hotseatRow, totalRows, duration);
+ }
+ }
+ if (staggerQsb) {
+ addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows, duration);
+ }
}
mAnimators.addListener(new AnimatorListenerAdapter() {
@@ -153,19 +169,19 @@
mAnimators.addListener(forEndCallback(launcher::resumeExpensiveViewUpdates));
if (animateOverviewScrim) {
- PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS);
+ PendingAnimation pendingAnimation = new PendingAnimation(duration);
launcher.getWorkspace().getStateTransitionAnimation()
.setScrim(pendingAnimation, NORMAL, new StateAnimationConfig());
mAnimators.play(pendingAnimation.buildAnim());
}
- addDepthAnimationForState(launcher, NORMAL, DURATION_MS);
+ addDepthAnimationForState(launcher, NORMAL, duration);
mAnimators.play(launcher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
- .setDuration(DURATION_MS));
+ .setDuration(duration));
}
- private void addAnimationForPage(CellLayout page, int totalRows) {
+ private void addAnimationForPage(CellLayout page, int totalRows, long duration) {
ShortcutAndWidgetContainer itemsContainer = page.getShortcutsAndWidgets();
boolean pageClipChildren = page.getClipChildren();
@@ -178,7 +194,7 @@
for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) {
View child = itemsContainer.getChildAt(i);
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
- addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
+ addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows, duration);
}
mAnimators.addListener(new AnimatorListenerAdapter() {
@@ -231,8 +247,9 @@
* @param v A view on the workspace.
* @param row The bottom-most row that contains the view.
* @param totalRows Total number of rows.
+ * @param duration duration of the animation
*/
- private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+ private void addStaggeredAnimationForView(View v, int row, int totalRows, long duration) {
if (mIgnoredView != null && mIgnoredView == v) return;
// Invert the rows, because we stagger starting from the bottom of the screen.
int invertedRow = totalRows - row;
@@ -266,7 +283,7 @@
v.setAlpha(0);
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
alpha.setInterpolator(LINEAR);
- alpha.setDuration(ALPHA_DURATION_MS);
+ alpha.setDuration(duration);
alpha.setStartDelay(startDelay);
alpha.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index b222f51..833d705 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -279,7 +279,10 @@
// get the final leash operations but do not apply to the leash.
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
- return onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
+ final PictureInPictureSurfaceTransaction pipTx =
+ onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
+ pipTx.setShouldDisableCanAffectSystemUiFlags(true);
+ return pipTx;
}
private RotatedPosition getRotatedPosition(float progress) {
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 19a48db..5dc4613 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -15,11 +15,20 @@
*/
package com.android.quickstep.util;
-import android.content.Context;
-import android.view.Display;
+import static android.view.Display.DEFAULT_DISPLAY;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
+import java.util.Set;
+
/**
* Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher
*/
@@ -30,17 +39,23 @@
}
@Override
- protected String getDisplayId(Display display) {
- return display.getUniqueId();
+ public int getRotation(Context displayInfoContext) {
+ return displayInfoContext.getResources().getConfiguration().windowConfiguration
+ .getRotation();
}
@Override
- public boolean isInternalDisplay(Display display) {
- return display.getType() == Display.TYPE_INTERNAL;
- }
-
- @Override
- public int getRotation(Context context) {
- return context.getResources().getConfiguration().windowConfiguration.getRotation();
+ public ArrayMap<CachedDisplayInfo, WindowBounds[]> estimateInternalDisplayBounds(
+ Context displayInfoContext) {
+ ArrayMap<CachedDisplayInfo, WindowBounds[]> result = new ArrayMap<>();
+ WindowManager windowManager = displayInfoContext.getSystemService(WindowManager.class);
+ Set<WindowMetrics> possibleMaximumWindowMetrics =
+ windowManager.getPossibleMaximumWindowMetrics(DEFAULT_DISPLAY);
+ for (WindowMetrics windowMetrics : possibleMaximumWindowMetrics) {
+ CachedDisplayInfo info = getDisplayInfo(windowMetrics, Surface.ROTATION_0);
+ WindowBounds[] bounds = estimateWindowBounds(displayInfoContext, info);
+ result.put(info, bounds);
+ }
+ return result;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index dbb20e0..1acdec1 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -390,10 +390,8 @@
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
- // When relativeLayer = 0, it reverts the surfaces back to the original order.
- builder.withRelativeLayerTo(params.getRecentsSurface(),
- mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ builder.withLayer(mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8f6fba7..12ddc38 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -141,8 +141,8 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
import com.android.launcher3.util.ViewPool;
@@ -4562,6 +4562,7 @@
new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
+ tx.setShouldDisableCanAffectSystemUiFlags(false);
int[] taskIds = TopTaskTracker.INSTANCE.get(getContext()).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
diff --git a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index 9e5d958..1c15e1e 100644
--- a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -35,7 +35,6 @@
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Size;
-import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
@@ -290,15 +289,17 @@
private DisplayController.Info createDisplayInfo(Size screenSize, int rotation) {
Point displaySize = new Point(screenSize.getWidth(), screenSize.getHeight());
RotationUtils.rotateSize(displaySize, rotation);
- CachedDisplayInfo cdi = new CachedDisplayInfo(displaySize, rotation);
- WindowBounds wm = new WindowBounds(
+ CachedDisplayInfo cachedDisplayInfo = new CachedDisplayInfo(displaySize, rotation);
+ WindowBounds windowBounds = new WindowBounds(
new Rect(0, 0, displaySize.x, displaySize.y),
new Rect());
WindowManagerProxy wmProxy = mock(WindowManagerProxy.class);
- doReturn(cdi).when(wmProxy).getDisplayInfo(any(), any());
- doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any());
+ doReturn(cachedDisplayInfo).when(wmProxy).getDisplayInfo(any());
+ doReturn(windowBounds).when(wmProxy).getRealBounds(any(), any());
+ ArrayMap<CachedDisplayInfo, WindowBounds[]> internalDisplayBounds = new ArrayMap<>();
+ doReturn(internalDisplayBounds).when(wmProxy).estimateInternalDisplayBounds(any());
return new DisplayController.Info(
- getApplicationContext(), mock(Display.class), wmProxy, new ArrayMap<>());
+ getApplicationContext(), wmProxy, new ArrayMap<>());
}
private float generateTouchRegionHeight(Size screenSize, int rotation) {
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 7d414f4..d43aafa 100644
--- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -23,8 +23,6 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.ArrayMap;
-import android.util.Pair;
-import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -148,7 +146,7 @@
int rotation = mDisplaySize.x > mDisplaySize.y
? Surface.ROTATION_90 : Surface.ROTATION_0;
CachedDisplayInfo cdi =
- new CachedDisplayInfo("test-display", mDisplaySize, rotation , new Rect());
+ new CachedDisplayInfo(mDisplaySize, rotation, new Rect());
WindowBounds wm = new WindowBounds(
new Rect(0, 0, mDisplaySize.x, mDisplaySize.y),
mDisplayInsets);
@@ -164,15 +162,15 @@
}
WindowManagerProxy wmProxy = mock(WindowManagerProxy.class);
- doReturn(cdi).when(wmProxy).getDisplayInfo(any(), any());
- doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any());
+ doReturn(cdi).when(wmProxy).getDisplayInfo(any());
+ doReturn(wm).when(wmProxy).getRealBounds(any(), any());
- ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache =
+ ArrayMap<CachedDisplayInfo, WindowBounds[]> perDisplayBoundsCache =
new ArrayMap<>();
- perDisplayBoundsCache.put(cdi.id, Pair.create(cdi.normalize(), allBounds));
+ perDisplayBoundsCache.put(cdi.normalize(), allBounds);
DisplayController.Info mockInfo = new Info(
- helper.sandboxContext, mock(Display.class), wmProxy, perDisplayBoundsCache);
+ helper.sandboxContext, wmProxy, perDisplayBoundsCache);
DisplayController controller =
DisplayController.INSTANCE.get(helper.sandboxContext);
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index f6a6156..0f1d933 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -22,6 +22,7 @@
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/all_apps_header"
+ android:layout_marginTop="@dimen/all_apps_header_bottom_padding"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -31,6 +32,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/all_apps_header"
+ android:layout_marginTop="@dimen/all_apps_header_bottom_padding"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 37ca89a..d23eac2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -161,12 +161,12 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"کاری"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"برنامههای کاری دارای نشان هستند و سرپرست سیستم میتواند آنها را ببیند"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"برنامههای کاری نشاندار هستند و سرپرست فناوری اطلاعات میتواند آنها را ببیند"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"متوجهام"</string>
<string name="work_apps_paused_title" msgid="3040901117349444598">"برنامههای کاری موقتاً متوقف شدهاند."</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"برنامههای کاری نمیتوانند برای شما اعلان ارسال کنند، از باتری استفاده کنند، یا به مکانتان دسترسی داشته باشند"</string>
<string name="work_apps_paused_content_description" msgid="5149623040804051095">"برنامههای کاری خاموش است. برنامههای کاری نمیتوانند برای شما اعلان ارسال کنند، از باتری استفاده کنند، یا به مکانتان دسترسی داشته باشند"</string>
- <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"برنامههای کاری دارای نشان هستند و سرپرست سیستم میتواند آنها را ببیند."</string>
+ <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"برنامههای کاری نشاندار هستند و سرپرست فناوری اطلاعات میتواند آنها را ببیند."</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"متوجهام"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"توقف موقت برنامههای کاری"</string>
<string name="work_apps_enable_btn_text" msgid="1156432622148413741">"روشن کردن برنامههای کاری"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index aea8195..fa2b789 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -75,7 +75,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ஆப்ஸ் தகவல்"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"ஆப்ஸைப் பரிந்துரைக்க வேண்டாம்"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"ஆப்ஸ் பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்ட ஆப்ஸைப் பின் செய்தல்"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 7bbdbd1..7a75ddb 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -56,4 +56,9 @@
<color name="workspace_accent_color_light">@android:color/system_accent1_100</color>
<color name="workspace_accent_color_dark">@android:color/system_accent2_600</color>
+
+ <color name="preload_icon_accent_color_light">@android:color/system_accent1_600</color>
+ <color name="preload_icon_background_color_light">@android:color/system_accent2_200</color>
+ <color name="preload_icon_accent_color_dark">@android:color/system_accent1_300</color>
+ <color name="preload_icon_background_color_dark">@android:color/system_neutral2_700</color>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 165ec5e..9f25905 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -53,6 +53,8 @@
<attr name="workProfileOverlayTextColor" format="color" />
<attr name="workspaceAccentColor" format="color" />
<attr name="dropTargetHoverTextColor" format="color" />
+ <attr name="preloadIconAccentColor" format="color" />
+ <attr name="preloadIconBackgroundColor" format="color" />
<attr name="allAppsButtonBgColor" format="color" />
<attr name="allAppsButtonColor1" format="color" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2bc9239..309a1c5 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -85,4 +85,9 @@
<color name="all_apps_button_color_2">#00677E</color>
<color name="all_apps_button_color_3">#5F757E</color>
<color name="all_apps_button_color_4">#005A6E</color>
+
+ <color name="preload_icon_accent_color_light">#00668B</color>
+ <color name="preload_icon_background_color_light">#B5CAD7</color>
+ <color name="preload_icon_accent_color_dark">#4BB6E8</color>
+ <color name="preload_icon_background_color_dark">#40484D</color>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 2109510..65bba7b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -65,6 +65,8 @@
<item name="workspaceAccentColor">@color/workspace_accent_color_light</item>
<item name="dropTargetHoverTextColor">@color/workspace_text_color_dark</item>
<item name="overviewScrimColor">@color/overview_scrim</item>
+ <item name="preloadIconAccentColor">@color/preload_icon_accent_color_light</item>
+ <item name="preloadIconBackgroundColor">@color/preload_icon_background_color_light</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
@@ -123,6 +125,8 @@
<item name="workProfileOverlayTextColor">@android:color/white</item>
<item name="eduHalfSheetBGColor">#DD000000</item>
<item name="overviewScrimColor">@color/overview_scrim_dark</item>
+ <item name="preloadIconAccentColor">@color/preload_icon_accent_color_dark</item>
+ <item name="preloadIconBackgroundColor">@color/preload_icon_background_color_dark</item>
</style>
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 87885f6..8c1f505 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1148,7 +1148,7 @@
private int getHotseatBottomPadding() {
if (isQsbInline) {
- return getQsbOffsetY() - (Math.abs(hotseatQsbHeight - hotseatCellHeightPx) / 2);
+ return getQsbOffsetY() + ((hotseatQsbHeight - hotseatCellHeightPx) / 2);
} else {
return (getQsbOffsetY() - taskbarSize) / 2;
}
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index d908440..c1304d4 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -194,9 +194,10 @@
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
firstButton.measure(widthSpec, heightSpec);
if (!mIsVertical) {
- // Remove icons and put the button's text on two lines if text is truncated.
+ // Remove both icons and put the button's text on two lines if text is truncated.
if (firstButton.isTextTruncated(availableWidth)) {
firstButton.setIconVisible(false);
+ secondButton.setIconVisible(false);
firstButton.setTextMultiLine(true);
firstButton.setPadding(horizontalPadding, verticalPadding / 2,
horizontalPadding, verticalPadding / 2);
@@ -209,8 +210,10 @@
}
secondButton.measure(widthSpec, heightSpec);
if (!mIsVertical) {
+ // Remove both icons and put the button's text on two lines if text is truncated.
if (secondButton.isTextTruncated(availableWidth)) {
secondButton.setIconVisible(false);
+ firstButton.setIconVisible(false);
secondButton.setTextMultiLine(true);
secondButton.setPadding(horizontalPadding, verticalPadding / 2,
horizontalPadding, verticalPadding / 2);
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 76106fc..8c4c662 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -206,6 +206,13 @@
getShortcutsAndWidgets().setAlpha(alpha);
}
+ /**
+ * Sets the alpha value of just our QSB.
+ */
+ public void setQsbAlpha(float alpha) {
+ mQsb.setAlpha(alpha);
+ }
+
public float getIconsAlpha() {
return getShortcutsAndWidgets().getAlpha();
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index db43b44..73ca4a3 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -234,7 +234,8 @@
/*allowDisabledGrid=*/false),
defaultDeviceType);
- Info myInfo = new Info(context, display);
+ Context displayContext = context.createDisplayContext(display);
+ Info myInfo = new Info(displayContext);
@DeviceType int deviceType = getDeviceType(myInfo);
DisplayOption myDisplayOption = invDistWeightedInterpolate(
myInfo,
@@ -642,7 +643,7 @@
+ "\nconfig: " + config
+ "\ndisplayMetrics: " + res.getDisplayMetrics()
+ "\nrotation: " + rotation
- + "\n" + stringWriter.toString(),
+ + "\n" + stringWriter,
new Exception());
}
return getBestMatch(screenWidth, screenHeight, rotation);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d26e1ab..ebed31b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2776,7 +2776,7 @@
View v = getFirstMatch(Collections.singletonList(activeRecyclerView),
preferredItem, packageAndUserAndApp);
- if (activeRecyclerView.getCurrentScrollY() > 0) {
+ if (v != null && activeRecyclerView.getCurrentScrollY() > 0) {
RectF locationBounds = new RectF();
FloatingIconView.getLocationBoundsForView(this, v, false, locationBounds,
new Rect());
@@ -2804,6 +2804,7 @@
* @param containers List of ViewGroups to scan, in order of preference.
* @param operators List of operators, in order starting from best matching operator.
*/
+ @Nullable
private static View getFirstMatch(Iterable<ViewGroup> containers,
final Predicate<ItemInfo>... operators) {
for (Predicate<ItemInfo> operator : operators) {
@@ -2821,6 +2822,7 @@
* Returns the first view matching the operator in the given ViewGroups, or null if none.
* Forward iteration matters.
*/
+ @Nullable
private static View mapOverViewGroup(ViewGroup container, Predicate<ItemInfo> op) {
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 808bf96..0c7c311 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -26,6 +26,7 @@
import android.util.IntProperty;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import android.widget.TextView;
import com.android.launcher3.util.MultiScalePropertyFactory;
@@ -115,6 +116,32 @@
}
};
+ public static final IntProperty<TextView> TEXT_COLOR =
+ new IntProperty<TextView>("textColor") {
+ @Override
+ public Integer get(TextView view) {
+ return view.getTextColors().getDefaultColor();
+ }
+
+ @Override
+ public void setValue(TextView view, int color) {
+ view.setTextColor(color);
+ }
+ };
+
+ public static final IntProperty<TextView> HINT_TEXT_COLOR =
+ new IntProperty<TextView>("hintTextColor") {
+ @Override
+ public Integer get(TextView view) {
+ return view.getHintTextColors().getDefaultColor();
+ }
+
+ @Override
+ public void setValue(TextView view, int color) {
+ view.setHintTextColor(color);
+ }
+ };
+
public static final FloatProperty<View> VIEW_TRANSLATE_X =
View.TRANSLATION_X instanceof FloatProperty ? (FloatProperty) View.TRANSLATION_X
: new FloatProperty<View>("translateX") {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 73be5be..cba0b7d 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1187,7 +1187,9 @@
}
public int getScrollForPage(int index) {
- if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
+ // TODO(b/233112195): Use !pageScrollsInitialized() instead of mPageScrolls == null, once we
+ // root cause where we should be using runOnPageScrollsInitialized().
+ if (mPageScrolls == null || index >= mPageScrolls.length || index < 0) {
return 0;
} else {
return mPageScrolls[index];
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 2cefc6c..499e749 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -128,6 +128,7 @@
private final int mScrimColor;
private final int mHeaderProtectionColor;
protected final float mHeaderThreshold;
+ private int mHeaderBottomAdjustment;
private ScrimView mScrimView;
private int mHeaderColor;
private int mTabsProtectionAlpha;
@@ -140,6 +141,8 @@
mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
mHeaderThreshold = getResources().getDimensionPixelSize(
R.dimen.dynamic_grid_cell_border_spacing);
+ mHeaderBottomAdjustment = getResources().getDimensionPixelSize(
+ R.dimen.all_apps_header_bottom_adjustment);
mHeaderProtectionColor = Themes.getAttrColor(context, R.attr.allappsHeaderProtectionColor);
mWorkManager = new WorkProfileManager(
@@ -301,6 +304,10 @@
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
return true;
}
+ if (isSearching()) {
+ // if in search state, consume touch event.
+ return true;
+ }
return false;
}
@@ -722,6 +729,9 @@
mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
int bottom = getHeaderBottom();
+ if (!mUsingTabs) {
+ bottom += getFloatingHeaderView().getPaddingBottom() - mHeaderBottomAdjustment;
+ }
canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
int tabsHeight = getFloatingHeaderView().getPeripheralProtectionHeight();
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 515f80a..6ecbad2 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -81,7 +81,6 @@
protected final Map<AllAppsRow, PluginHeaderRow> mPluginRows = new ArrayMap<>();
- private final int mHeaderTopPadding;
// These two values are necessary to ensure that the header protection is drawn correctly.
private final int mHeaderTopAdjustment;
private final int mHeaderBottomAdjustment;
@@ -118,8 +117,6 @@
public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
- mHeaderTopPadding = context.getResources()
- .getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
mHeaderTopAdjustment = context.getResources()
.getDimensionPixelSize(R.dimen.all_apps_header_top_adjustment);
mHeaderBottomAdjustment = context.getResources()
@@ -209,7 +206,7 @@
int oldMaxHeight = mMaxTranslation;
updateExpectedHeight();
- if (mMaxTranslation != oldMaxHeight) {
+ if (mMaxTranslation != oldMaxHeight || mCollapsed) {
BaseAllAppsContainerView<?> parent = (BaseAllAppsContainerView<?>) getParent();
if (parent != null) {
parent.setupHeader();
@@ -326,7 +323,7 @@
int uncappedTranslationY = mTranslationY;
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- if (mCollapsed || uncappedTranslationY < mTranslationY - mHeaderTopPadding) {
+ if (mCollapsed || uncappedTranslationY < mTranslationY - getPaddingTop()) {
// we hide it completely if already capped (for opening search anim)
for (FloatingHeaderRow row : mAllRows) {
row.setVerticalScroll(0, true /* isScrolledOut */);
@@ -339,7 +336,10 @@
mTabLayout.setTranslationY(mTranslationY);
- int clipTop = mHeaderTopPadding - mHeaderTopAdjustment;
+ int clipTop = getPaddingTop() - mHeaderTopAdjustment;
+ if (mTabsHidden) {
+ clipTop += getPaddingBottom() - mHeaderBottomAdjustment;
+ }
mRVClip.top = mTabsHidden ? clipTop : 0;
mHeaderClip.top = clipTop;
// clipping on a draw might cause additional redraw
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index b70cb13..8443923 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -158,10 +158,10 @@
workFabMarginBottom += mAllApps.mActivityContext.getDeviceProfile().getInsets().bottom;
}
lp.bottomMargin = workFabMarginBottom;
- int totalScreenWidth = mDeviceProfile.widthPx;
+ int allAppsContainerWidth = mAllApps.getVisibleContainerView().getWidth();
int personalWorkTabWidth =
mAllApps.mActivityContext.getAppsView().getFloatingHeaderView().getTabWidth();
- lp.rightMargin = lp.leftMargin = (totalScreenWidth - personalWorkTabWidth) / 2;
+ lp.rightMargin = lp.leftMargin = (allAppsContainerWidth - personalWorkTabWidth) / 2;
if (mWorkModeSwitch.getParent() != mAllApps) {
mAllApps.addView(mWorkModeSwitch);
}
diff --git a/src/com/android/launcher3/anim/AnimatedPropertySetter.java b/src/com/android/launcher3/anim/AnimatedPropertySetter.java
index 01301f2..82e645a 100644
--- a/src/com/android/launcher3/anim/AnimatedPropertySetter.java
+++ b/src/com/android/launcher3/anim/AnimatedPropertySetter.java
@@ -97,6 +97,18 @@
return anim;
}
+ @NonNull
+ @Override
+ public <T> Animator setColor(T target, IntProperty<T> property, int value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return NO_OP;
+ }
+ Animator anim = ObjectAnimator.ofArgb(target, property, value);
+ anim.setInterpolator(interpolator);
+ add(anim);
+ return anim;
+ }
/**
* Adds a callback to be run on every frame of the animation
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index d2207f6..b0ed2d2 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -89,6 +89,16 @@
}
/**
+ * Updates a color property of the target using the provided interpolator
+ */
+ @NonNull
+ public <T> Animator setColor(T target, IntProperty<T> property, int value,
+ TimeInterpolator interpolator) {
+ property.setValue(target, value);
+ return NO_OP;
+ }
+
+ /**
* Runs the animation as part of setting the property
*/
public abstract void add(Animator animatorSet);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7e953af..38b5c65 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -96,6 +96,9 @@
public static final BooleanFlag ENABLE_QUICK_SEARCH = new DeviceFlag("ENABLE_QUICK_SEARCH",
true, "Use quick search behavior.");
+ public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
+ true, "Hide header on keyboard before typing in all apps");
+
public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
"COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
@@ -262,8 +265,8 @@
public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
"ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
- public static final BooleanFlag ENABLE_SHOW_KEYBOARD_IN_ALL_APPS = new DeviceFlag(
- "ENABLE_SHOW_KEYBOARD_IN_ALL_APPS", true,
+ public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = new DeviceFlag(
+ "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
"Enable option to show keyboard when going to all-apps");
public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 6355b62..2e5f2e5 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -79,6 +79,8 @@
private int mPrevTopPadding = -1;
private Drawable mReferenceDrawable = null;
+ private int mNumOfPrevItems = 0;
+
// These hold the first page preview items
private ArrayList<PreviewItemDrawingParams> mFirstPageParams = new ArrayList<>();
// These hold the current page preview items. It is empty if the current page is the first page.
@@ -254,7 +256,6 @@
void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
List<WorkspaceItemInfo> items = mIcon.getPreviewItemsOnPage(page);
- int prevNumItems = params.size();
// We adjust the size of the list to match the number of items in the preview.
while (items.size() < params.size()) {
@@ -278,8 +279,9 @@
mReferenceDrawable = p.drawable;
}
} else {
- FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
- numItemsInFirstPagePreview, DROP_IN_ANIMATION_DURATION, null);
+ FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i,
+ mNumOfPrevItems, i, numItemsInFirstPagePreview, DROP_IN_ANIMATION_DURATION,
+ null);
if (p.anim != null) {
if (p.anim.hasEqualFinalState(anim)) {
@@ -318,7 +320,9 @@
}
void updatePreviewItems(boolean animate) {
+ int numOfPrevItemsAux = mFirstPageParams.size();
buildParamsForPage(0, mFirstPageParams, animate);
+ mNumOfPrevItems = numOfPrevItemsAux;
}
void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index d2e4c51..0eb86b1 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -28,11 +28,9 @@
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
-import android.util.Pair;
import android.util.Property;
-import android.util.SparseArray;
-import android.view.ContextThemeWrapper;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -40,8 +38,6 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.Themes;
-import java.lang.ref.WeakReference;
-
/**
* Extension of {@link FastBitmapDrawable} which shows a progress bar around the icon.
*/
@@ -61,9 +57,9 @@
};
private static final int DEFAULT_PATH_SIZE = 100;
- private static final float PROGRESS_WIDTH = 7;
- private static final float PROGRESS_GAP = 2;
private static final int MAX_PAINT_ALPHA = 255;
+ private static final int TRACK_ALPHA = (int) (0.27f * MAX_PAINT_ALPHA);
+ private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA);
private static final long DURATION_SCALE = 500;
@@ -71,13 +67,8 @@
// Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE
private static final float COMPLETE_ANIM_FRACTION = 0.3f;
- private static final int COLOR_TRACK = 0x77EEEEEE;
- private static final int COLOR_SHADOW = 0x55000000;
-
- private static final float SMALL_SCALE = 0.6f;
-
- private static final SparseArray<WeakReference<Pair<Path, Bitmap>>> sShadowCache =
- new SparseArray<>();
+ private static final float SMALL_SCALE = 0.7f;
+ private static final float PROGRESS_STROKE_SCALE = 0.075f;
private static final int PRELOAD_ACCENT_COLOR_INDEX = 0;
private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1;
@@ -94,7 +85,6 @@
private final Path mScaledProgressPath;
private final Paint mProgressPaint;
- private Bitmap mShadowBitmap;
private final int mIndicatorColor;
private final int mSystemAccentColor;
private final int mSystemBackgroundColor;
@@ -134,7 +124,6 @@
mScaledProgressPath = new Path();
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
- mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
mIndicatorColor = indicatorColor;
@@ -149,47 +138,22 @@
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
+
+ float progressWidth = PROGRESS_STROKE_SCALE * bounds.width();
mTmpMatrix.setScale(
- (bounds.width() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / DEFAULT_PATH_SIZE,
- (bounds.height() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / DEFAULT_PATH_SIZE);
- mTmpMatrix.postTranslate(
- bounds.left + PROGRESS_WIDTH + PROGRESS_GAP,
- bounds.top + PROGRESS_WIDTH + PROGRESS_GAP);
+ (bounds.width() - 2 * progressWidth) / DEFAULT_PATH_SIZE,
+ (bounds.height() - 2 * progressWidth) / DEFAULT_PATH_SIZE);
+ mTmpMatrix.postTranslate(bounds.left + progressWidth, bounds.top + progressWidth);
mShapePath.transform(mTmpMatrix, mScaledTrackPath);
- float scale = bounds.width() / DEFAULT_PATH_SIZE;
- mProgressPaint.setStrokeWidth(PROGRESS_WIDTH * scale);
+ mProgressPaint.setStrokeWidth(progressWidth);
- mShadowBitmap = getShadowBitmap(bounds.width(), bounds.height(),
- (PROGRESS_GAP ) * scale);
mPathMeasure.setPath(mScaledTrackPath, true);
mTrackLength = mPathMeasure.getLength();
setInternalProgress(mInternalStateProgress);
}
- private Bitmap getShadowBitmap(int width, int height, float shadowRadius) {
- int key = ((width << 16) | height) * (mIsDarkMode ? -1 : 1);
- WeakReference<Pair<Path, Bitmap>> shadowRef = sShadowCache.get(key);
- Pair<Path, Bitmap> cache = shadowRef != null ? shadowRef.get() : null;
- Bitmap shadow = cache != null && cache.first.equals(mShapePath) ? cache.second : null;
- if (shadow != null) {
- return shadow;
- }
- shadow = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(shadow);
- mProgressPaint.setShadowLayer(shadowRadius, 0, 0, mIsStartable
- ? COLOR_SHADOW : mSystemAccentColor);
- mProgressPaint.setColor(mIsStartable ? COLOR_TRACK : mSystemBackgroundColor);
- mProgressPaint.setAlpha(MAX_PAINT_ALPHA);
- c.drawPath(mScaledTrackPath, mProgressPaint);
- mProgressPaint.clearShadowLayer();
- c.setBitmap(null);
-
- sShadowCache.put(key, new WeakReference<>(Pair.create(mShapePath, shadow)));
- return shadow;
- }
-
@Override
public void drawInternal(Canvas canvas, Rect bounds) {
if (mRanFinishAnimation) {
@@ -197,12 +161,17 @@
return;
}
- // Draw track.
+ // Draw background.
+ mProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ mProgressPaint.setColor(mSystemBackgroundColor);
+ canvas.drawPath(mScaledTrackPath, mProgressPaint);
+
+ // Draw track and progress.
+ mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setColor(mIsStartable ? mIndicatorColor : mSystemAccentColor);
+ mProgressPaint.setAlpha(TRACK_ALPHA);
+ canvas.drawPath(mScaledTrackPath, mProgressPaint);
mProgressPaint.setAlpha(mTrackAlpha);
- if (mShadowBitmap != null) {
- canvas.drawBitmap(mShadowBitmap, bounds.left, bounds.top, mProgressPaint);
- }
canvas.drawPath(mScaledProgressPath, mProgressPaint);
int saveCount = canvas.save();
@@ -211,6 +180,11 @@
canvas.restoreToCount(saveCount);
}
+ @Override
+ protected void updateFilter() {
+ setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA);
+ }
+
/**
* Updates the install progress based on the level
*/
@@ -326,13 +300,12 @@
}
private static int[] getPreloadColors(Context context) {
- Context dayNightThemeContext = new ContextThemeWrapper(
- context, android.R.style.Theme_DeviceDefault_DayNight);
int[] preloadColors = new int[2];
- preloadColors[PRELOAD_ACCENT_COLOR_INDEX] = Themes.getColorAccent(dayNightThemeContext);
- preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX] = Themes.getColorBackgroundFloating(
- dayNightThemeContext);
+ preloadColors[PRELOAD_ACCENT_COLOR_INDEX] = Themes.getAttrColor(context,
+ R.attr.preloadIconAccentColor);
+ preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX] = Themes.getAttrColor(context,
+ R.attr.preloadIconBackgroundColor);
return preloadColors;
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 5dcd48c..c4ec4e3 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -735,7 +735,9 @@
UNKNOWN(0),
COLD(1),
HOT(2),
- TIMEOUT(3);
+ TIMEOUT(3),
+ FAIL(4),
+ COLD_USERWAITING(5);
private final int mId;
@@ -772,6 +774,13 @@
}
/**
+ * Sets query length of the event.
+ */
+ default StatsLatencyLogger withQueryLength(int queryLength) {
+ return this;
+ }
+
+ /**
* Sets packageId of log message.
*/
default StatsLatencyLogger withPackageId(int packageId) {
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 9ed6bee..1a77674 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -41,7 +41,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
import android.view.Display;
import androidx.annotation.AnyThread;
@@ -117,8 +116,9 @@
getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
- mInfo = new Info(getDisplayInfoContext(display), display,
- wmProxy, wmProxy.estimateInternalDisplayBounds(context));
+ Context displayInfoContext = getDisplayInfoContext(display);
+ mInfo = new Info(displayInfoContext, wmProxy,
+ wmProxy.estimateInternalDisplayBounds(displayInfoContext));
}
/**
@@ -216,18 +216,18 @@
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
- Context displayContext = getDisplayInfoContext(display);
- Info newInfo = new Info(displayContext, display, wmProxy, oldInfo.mPerDisplayBounds);
+ Context displayInfoContext = getDisplayInfoContext(display);
+ Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
|| newInfo.navigationMode != oldInfo.navigationMode) {
// Cache may not be valid anymore, recreate without cache
- newInfo = new Info(displayContext, display, wmProxy,
- wmProxy.estimateInternalDisplayBounds(displayContext));
+ newInfo = new Info(displayInfoContext, wmProxy,
+ wmProxy.estimateInternalDisplayBounds(displayInfoContext));
}
int change = 0;
- if (!newInfo.displayId.equals(oldInfo.displayId)) {
+ if (!newInfo.normalizedDisplayInfo.equals(oldInfo.normalizedDisplayInfo)) {
change |= CHANGE_ACTIVE_SCREEN;
}
if (newInfo.rotation != oldInfo.rotation) {
@@ -242,35 +242,16 @@
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)
|| !newInfo.mPerDisplayBounds.equals(oldInfo.mPerDisplayBounds)) {
change |= CHANGE_SUPPORTED_BOUNDS;
-
- Point currentS = newInfo.currentSize;
- Pair<CachedDisplayInfo, WindowBounds[]> cachedBounds =
- oldInfo.mPerDisplayBounds.get(newInfo.displayId);
- Point expectedS = cachedBounds == null ? null : cachedBounds.first.size;
- if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) {
- Log.e("b/198965093",
- "Inconsistent number of displays"
- + "\ndisplay state: " + display.getState()
- + "\noldInfo.supportedBounds: " + oldInfo.supportedBounds
- + "\nnewInfo.supportedBounds: " + newInfo.supportedBounds);
- }
- if (expectedS != null
- && (Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y)
- || Math.max(currentS.x, currentS.y) != Math.max(expectedS.x, expectedS.y))
- && display.getState() == Display.STATE_OFF) {
- Log.e("b/198965093",
- "Display size changed while display is off, ignoring change");
- return;
- }
}
Log.d("b/198965093", "handleInfoChange"
- + "\n\tchange: " + change
- + "\n\tConfiguration diff: " + newInfo.mConfiguration.diff(oldInfo.mConfiguration));
+ + "\n\tchange: 0b" + Integer.toBinaryString(change)
+ + "\n\tConfiguration diff: 0x" + Integer.toHexString(
+ newInfo.mConfiguration.diff(oldInfo.mConfiguration)));
if (change != 0) {
mInfo = newInfo;
final int flags = change;
- MAIN_EXECUTOR.execute(() -> notifyChange(displayContext, flags));
+ MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags));
}
}
@@ -288,8 +269,8 @@
public static class Info {
// Cached property
+ public final CachedDisplayInfo normalizedDisplayInfo;
public final int rotation;
- public final String displayId;
public final Point currentSize;
public final Rect cutout;
@@ -302,60 +283,71 @@
public final Set<WindowBounds> supportedBounds = new ArraySet<>();
- private final ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> mPerDisplayBounds =
+ private final ArrayMap<CachedDisplayInfo, WindowBounds[]> mPerDisplayBounds =
new ArrayMap<>();
// TODO(b/198965093): Remove after investigation
private Configuration mConfiguration;
- public Info(Context context, Display display) {
+ public Info(Context displayInfoContext) {
/* don't need system overrides for external displays */
- this(context, display, new WindowManagerProxy(), new ArrayMap<>());
+ this(displayInfoContext, new WindowManagerProxy(), new ArrayMap<>());
}
// Used for testing
- public Info(Context context, Display display,
+ public Info(Context displayInfoContext,
WindowManagerProxy wmProxy,
- ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache) {
- CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(context, display);
+ ArrayMap<CachedDisplayInfo, WindowBounds[]> perDisplayBoundsCache) {
+ CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(displayInfoContext);
+ normalizedDisplayInfo = displayInfo.normalize();
rotation = displayInfo.rotation;
currentSize = displayInfo.size;
- displayId = displayInfo.id;
cutout = displayInfo.cutout;
- Configuration config = context.getResources().getConfiguration();
+ Configuration config = displayInfoContext.getResources().getConfiguration();
fontScale = config.fontScale;
densityDpi = config.densityDpi;
mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp);
- navigationMode = parseNavigationMode(context);
+ navigationMode = parseNavigationMode(displayInfoContext);
// TODO(b/198965093): Remove after investigation
mConfiguration = config;
mPerDisplayBounds.putAll(perDisplayBoundsCache);
- Pair<CachedDisplayInfo, WindowBounds[]> cachedValue = mPerDisplayBounds.get(displayId);
+ WindowBounds[] cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo);
- WindowBounds realBounds = wmProxy.getRealBounds(context, display, displayInfo);
+ WindowBounds realBounds = wmProxy.getRealBounds(displayInfoContext, displayInfo);
if (cachedValue == null) {
- supportedBounds.add(realBounds);
- } else {
+ // Unexpected normalizedDisplayInfo is found, recreate the cache
+ Log.e("b/198965093", "Unexpected normalizedDisplayInfo found, invalidating cache");
+ mPerDisplayBounds.clear();
+ mPerDisplayBounds.putAll(wmProxy.estimateInternalDisplayBounds(displayInfoContext));
+ cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo);
+ if (cachedValue == null) {
+ Log.e("b/198965093", "normalizedDisplayInfo not found in estimation: "
+ + normalizedDisplayInfo);
+ supportedBounds.add(realBounds);
+ }
+ }
+
+ if (cachedValue != null) {
// Verify that the real bounds are a match
- WindowBounds expectedBounds = cachedValue.second[displayInfo.rotation];
+ WindowBounds expectedBounds = cachedValue[displayInfo.rotation];
if (!realBounds.equals(expectedBounds)) {
WindowBounds[] clone = new WindowBounds[4];
- System.arraycopy(cachedValue.second, 0, clone, 0, 4);
+ System.arraycopy(cachedValue, 0, clone, 0, 4);
clone[displayInfo.rotation] = realBounds;
- cachedValue = Pair.create(displayInfo.normalize(), clone);
- mPerDisplayBounds.put(displayId, cachedValue);
+ mPerDisplayBounds.put(normalizedDisplayInfo, clone);
}
}
mPerDisplayBounds.values().forEach(
- pair -> Collections.addAll(supportedBounds, pair.second));
+ windowBounds -> Collections.addAll(supportedBounds, windowBounds));
Log.e("b/198965093", "mConfiguration: " + mConfiguration);
Log.d("b/198965093", "displayInfo: " + displayInfo);
Log.d("b/198965093", "realBounds: " + realBounds);
- mPerDisplayBounds.values().forEach(pair -> Log.d("b/198965093",
- "perDisplayBounds - " + pair.first + ": " + Arrays.deepToString(pair.second)));
+ Log.d("b/198965093", "normalizedDisplayInfo: " + normalizedDisplayInfo);
+ mPerDisplayBounds.forEach((key, value) -> Log.d("b/198965093",
+ "perDisplayBounds - " + key + ": " + Arrays.deepToString(value)));
}
/**
@@ -383,14 +375,14 @@
public void dump(PrintWriter pw) {
Info info = mInfo;
pw.println("DisplayController.Info:");
- pw.println(" id=" + info.displayId);
+ pw.println(" normalizedDisplayInfo=" + info.normalizedDisplayInfo);
pw.println(" rotation=" + info.rotation);
pw.println(" fontScale=" + info.fontScale);
pw.println(" densityDpi=" + info.densityDpi);
pw.println(" navigationMode=" + info.navigationMode.name());
pw.println(" currentSize=" + info.currentSize);
- info.mPerDisplayBounds.values().forEach(pair -> pw.println(
- " perDisplayBounds - " + pair.first + ": " + Arrays.deepToString(pair.second)));
+ info.mPerDisplayBounds.forEach((key, value) -> pw.println(
+ " perDisplayBounds - " + key + ": " + Arrays.deepToString(value)));
}
/**
diff --git a/src/com/android/launcher3/util/HorizontalInsettableView.java b/src/com/android/launcher3/util/HorizontalInsettableView.java
index 7979bc0..486b73d 100644
--- a/src/com/android/launcher3/util/HorizontalInsettableView.java
+++ b/src/com/android/launcher3/util/HorizontalInsettableView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.util;
+import android.util.FloatProperty;
+
/**
* Allows the implementing view to add insets to the left and right.
*/
@@ -32,4 +34,22 @@
*/
void setHorizontalInsets(float insetPercentage);
+ /**
+ * Returns the width percentage to inset the content from the left and from the right. See
+ * {@link #setHorizontalInsets};
+ */
+ float getHorizontalInsets();
+
+ FloatProperty<HorizontalInsettableView> HORIZONTAL_INSETS =
+ new FloatProperty<HorizontalInsettableView>("horizontalInsets") {
+ @Override
+ public Float get(HorizontalInsettableView view) {
+ return view.getHorizontalInsets();
+ }
+
+ @Override
+ public void setValue(HorizontalInsettableView view, float insetPercentage) {
+ view.setHorizontalInsets(insetPercentage);
+ }
+ };
}
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index 8df3f8a..7e6711f 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -69,10 +69,6 @@
activityContext.getStatsLogManager().logger()
.log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
return;
- } else {
- // print which stack trace failed.
- Log.e("Launcher", "hideKeyboard ignored.", new Exception());
- // Then attempt to use the old logic.
}
}
// Since the launcher context cannot be accessed directly from callback, adding secondary
diff --git a/src/com/android/launcher3/util/window/CachedDisplayInfo.java b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
index 06b9829..23f37aa 100644
--- a/src/com/android/launcher3/util/window/CachedDisplayInfo.java
+++ b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
@@ -30,7 +30,6 @@
*/
public class CachedDisplayInfo {
- public final String id;
public final Point size;
public final int rotation;
public final Rect cutout;
@@ -40,11 +39,10 @@
}
public CachedDisplayInfo(Point size, int rotation) {
- this("", size, rotation, new Rect());
+ this(size, rotation, new Rect());
}
- public CachedDisplayInfo(String id, Point size, int rotation, Rect cutout) {
- this.id = id;
+ public CachedDisplayInfo(Point size, int rotation, Rect cutout) {
this.size = size;
this.rotation = rotation;
this.cutout = cutout;
@@ -62,16 +60,15 @@
Rect newCutout = new Rect(cutout);
rotateRect(newCutout, deltaRotation(rotation, Surface.ROTATION_0));
- return new CachedDisplayInfo(id, newSize, Surface.ROTATION_0, newCutout);
+ return new CachedDisplayInfo(newSize, Surface.ROTATION_0, newCutout);
}
@Override
public String toString() {
return "CachedDisplayInfo{"
- + "id='" + id + '\''
- + ", size=" + size
- + ", rotation=" + rotation
+ + "size=" + size
+ ", cutout=" + cutout
+ + ", rotation=" + rotation
+ '}';
}
@@ -80,13 +77,13 @@
if (this == o) return true;
if (!(o instanceof CachedDisplayInfo)) return false;
CachedDisplayInfo that = (CachedDisplayInfo) o;
- return rotation == that.rotation && Objects.equals(id, that.id)
- && Objects.equals(size, that.size) && Objects.equals(cutout,
- that.cutout);
+ return rotation == that.rotation
+ && Objects.equals(size, that.size)
+ && Objects.equals(cutout, that.cutout);
}
@Override
public int hashCode() {
- return Objects.hash(id, size, rotation, cutout);
+ return Objects.hash(size, rotation, cutout);
}
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 92f718e..d5a065a 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -16,7 +16,6 @@
package com.android.launcher3.util.window;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
@@ -41,7 +40,6 @@
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.util.ArrayMap;
-import android.util.Pair;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Surface;
@@ -88,20 +86,12 @@
* Returns a map of normalized info of internal displays to estimated window bounds
* for that display
*/
- public ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> estimateInternalDisplayBounds(
- Context context) {
- Display[] displays = context.getSystemService(DisplayManager.class).getDisplays();
- ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> result = new ArrayMap<>();
- for (Display display : displays) {
- if (isInternalDisplay(display)) {
- Context displayContext = Utilities.ATLEAST_S
- ? context.createWindowContext(display, TYPE_APPLICATION, null)
- : context.createDisplayContext(display);
- CachedDisplayInfo info = getDisplayInfo(displayContext, display).normalize();
- WindowBounds[] bounds = estimateWindowBounds(context, info);
- result.put(info.id, Pair.create(info, bounds));
- }
- }
+ public ArrayMap<CachedDisplayInfo, WindowBounds[]> estimateInternalDisplayBounds(
+ Context displayInfoContext) {
+ CachedDisplayInfo info = getDisplayInfo(displayInfoContext).normalize();
+ WindowBounds[] bounds = estimateWindowBounds(displayInfoContext, info);
+ ArrayMap<CachedDisplayInfo, WindowBounds[]> result = new ArrayMap<>();
+ result.put(info, bounds);
return result;
}
@@ -109,12 +99,11 @@
* Returns the real bounds for the provided display after applying any insets normalization
*/
@TargetApi(Build.VERSION_CODES.R)
- public WindowBounds getRealBounds(Context windowContext,
- Display display, CachedDisplayInfo info) {
+ public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
if (!Utilities.ATLEAST_R) {
Point smallestSize = new Point();
Point largestSize = new Point();
- display.getCurrentSizeRange(smallestSize, largestSize);
+ getDisplay(displayInfoContext).getCurrentSizeRange(smallestSize, largestSize);
if (info.size.y > info.size.x) {
// Portrait
@@ -122,17 +111,16 @@
info.rotation);
} else {
// Landscape
- new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
+ return new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
info.rotation);
}
}
- WindowMetrics wm = windowContext.getSystemService(WindowManager.class)
+ WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
.getMaximumWindowMetrics();
-
Rect insets = new Rect();
- normalizeWindowInsets(windowContext, wm.getWindowInsets(), insets);
- return new WindowBounds(wm.getBounds(), insets, info.rotation);
+ normalizeWindowInsets(displayInfoContext, windowMetrics.getWindowInsets(), insets);
+ return new WindowBounds(windowMetrics.getBounds(), insets, info.rotation);
}
/**
@@ -169,12 +157,9 @@
insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
Insets statusBarInsets = oldInsets.getInsets(WindowInsets.Type.statusBars());
-
-
int statusBarHeight = getDimenByName(systemRes,
(isPortrait) ? STATUS_BAR_HEIGHT_PORTRAIT : STATUS_BAR_HEIGHT_LANDSCAPE,
STATUS_BAR_HEIGHT);
-
Insets newStatusBarInsets = Insets.of(
statusBarInsets.left,
Math.max(statusBarInsets.top, statusBarHeight),
@@ -202,21 +187,14 @@
}
/**
- * Returns true if the display is an internal displays
- */
- protected boolean isInternalDisplay(Display display) {
- return display.getDisplayId() == Display.DEFAULT_DISPLAY;
- }
-
- /**
* Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations
*/
- public WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo display) {
+ protected WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo displayInfo) {
int densityDpi = context.getResources().getConfiguration().densityDpi;
- int rotation = display.rotation;
- Rect safeCutout = display.cutout;
+ int rotation = displayInfo.rotation;
+ Rect safeCutout = displayInfo.cutout;
- int minSize = Math.min(display.size.x, display.size.y);
+ int minSize = Math.min(displayInfo.size.x, displayInfo.size.y);
int swDp = (int) dpiFromPx(minSize, densityDpi);
Resources systemRes;
@@ -255,7 +233,7 @@
Point tempSize = new Point();
for (int i = 0; i < 4; i++) {
int rotationChange = deltaRotation(rotation, i);
- tempSize.set(display.size.x, display.size.y);
+ tempSize.set(displayInfo.size.x, displayInfo.size.y);
rotateSize(tempSize, rotationChange);
Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y);
@@ -311,48 +289,58 @@
* Returns a CachedDisplayInfo initialized for the current display
*/
@TargetApi(Build.VERSION_CODES.S)
- public CachedDisplayInfo getDisplayInfo(Context displayContext, Display display) {
- int rotation = getRotation(displayContext);
- Rect cutoutRect = new Rect();
- Point size = new Point();
+ public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
+ int rotation = getRotation(displayInfoContext);
if (Utilities.ATLEAST_S) {
- WindowMetrics wm = displayContext.getSystemService(WindowManager.class)
+ WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
.getMaximumWindowMetrics();
- DisplayCutout cutout = wm.getWindowInsets().getDisplayCutout();
- if (cutout != null) {
- cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
- cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
- }
-
- size.set(wm.getBounds().right, wm.getBounds().bottom);
+ return getDisplayInfo(windowMetrics, rotation);
} else {
+ Point size = new Point();
+ Display display = getDisplay(displayInfoContext);
display.getRealSize(size);
+ Rect cutoutRect = new Rect();
+ return new CachedDisplayInfo(size, rotation, cutoutRect);
}
- return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutoutRect);
}
/**
- * Returns a unique ID representing the display
+ * Returns a CachedDisplayInfo initialized for the current display
*/
- protected String getDisplayId(Display display) {
- return Integer.toString(display.getDisplayId());
+ @TargetApi(Build.VERSION_CODES.S)
+ protected CachedDisplayInfo getDisplayInfo(WindowMetrics windowMetrics, int rotation) {
+ Point size = new Point(windowMetrics.getBounds().right, windowMetrics.getBounds().bottom);
+ Rect cutoutRect = new Rect();
+ DisplayCutout cutout = windowMetrics.getWindowInsets().getDisplayCutout();
+ if (cutout != null) {
+ cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
+ cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
+ }
+ return new CachedDisplayInfo(size, rotation, cutoutRect);
}
/**
- * Returns rotation of the display associated with the context.
+ * Returns rotation of the display associated with the context, or rotation of DEFAULT_DISPLAY
+ * if the context isn't associated with a display.
*/
- public int getRotation(Context context) {
- Display d = null;
+ public int getRotation(Context displayInfoContext) {
+ return getDisplay(displayInfoContext).getRotation();
+ }
+
+ /**
+ *
+ * Returns the display associated with the context, or DEFAULT_DISPLAY if the context isn't
+ * associated with a display.
+ */
+ protected Display getDisplay(Context displayInfoContext) {
if (Utilities.ATLEAST_R) {
try {
- d = context.getDisplay();
+ return displayInfoContext.getDisplay();
} catch (UnsupportedOperationException e) {
// Ignore
}
}
- if (d == null) {
- d = context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- }
- return d.getRotation();
+ return displayInfoContext.getSystemService(DisplayManager.class).getDisplay(
+ DEFAULT_DISPLAY);
}
}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index acdd9a1..efc83eb 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -58,6 +58,8 @@
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.DeepShortcutView;
+import java.util.function.Supplier;
+
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
@@ -295,9 +297,11 @@
drawable = drawable == null ? null : drawable.getConstantState().newDrawable();
int iconOffset = getOffsetForIconBounds(l, drawable, pos);
+ // Clone right away as we are on the background thread instead of blocking the
+ // main thread later
+ Drawable btvClone = btvIcon == null ? null : btvIcon.getConstantState().newDrawable();
synchronized (outIconLoadResult) {
- outIconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
- ? null : btvIcon.getConstantState().newDrawable();
+ outIconLoadResult.btvDrawable = () -> btvClone;
outIconLoadResult.drawable = drawable;
outIconLoadResult.badge = badge;
outIconLoadResult.iconOffset = iconOffset;
@@ -318,7 +322,7 @@
*/
@UiThread
private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
- @Nullable Drawable btvIcon, int iconOffset) {
+ @Nullable Supplier<Drawable> btvIcon, int iconOffset) {
final DeviceProfile dp = mLauncher.getDeviceProfile();
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
@@ -361,9 +365,9 @@
*
* Allows nullable as this may be cleared when drawing is deferred to ClipIconView.
*/
- private void setOriginalDrawableBackground(@Nullable Drawable btvIcon) {
+ private void setOriginalDrawableBackground(@Nullable Supplier<Drawable> btvIcon) {
if (!mIsOpening) {
- mBtvDrawable.setBackground(btvIcon);
+ mBtvDrawable.setBackground(btvIcon == null ? null : btvIcon.get());
}
}
@@ -518,21 +522,26 @@
getLocationBoundsForView(l, v, isOpening, position);
final FastBitmapDrawable btvIcon;
+ final Supplier<Drawable> btvDrawableSupplier;
if (v instanceof BubbleTextView) {
BubbleTextView btv = (BubbleTextView) v;
if (info instanceof ItemInfoWithIcon
&& (((ItemInfoWithIcon) info).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
btvIcon = btv.makePreloadIcon();
+ btvDrawableSupplier = () -> btvIcon;
} else {
- btvIcon = (FastBitmapDrawable) btv.getIcon().getConstantState().newDrawable();
+ btvIcon = btv.getIcon();
+ // Clone when needed
+ btvDrawableSupplier = () -> btvIcon.getConstantState().newDrawable();
}
} else {
btvIcon = null;
+ btvDrawableSupplier = null;
}
IconLoadResult result = new IconLoadResult(info, btvIcon != null && btvIcon.isThemed());
- result.btvDrawable = btvIcon;
+ result.btvDrawable = btvDrawableSupplier;
final long fetchIconId = sFetchIconId++;
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
@@ -647,7 +656,7 @@
private static class IconLoadResult {
final ItemInfo itemInfo;
final boolean isThemed;
- Drawable btvDrawable;
+ Supplier<Drawable> btvDrawable;
Drawable drawable;
Drawable badge;
int iconOffset;
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index cc2b440..11ca130 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -285,8 +285,6 @@
}
break;
case MotionEvent.ACTION_UP:
- hideKeyboardAsync(ActivityContext.lookupContext(getContext()),
- getApplicationWindowToken());
case MotionEvent.ACTION_CANCEL:
mRv.onFastScrollCompleted();
mTouchOffsetY = 0;
@@ -310,6 +308,7 @@
}
private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
+ hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getWindowToken());
mIsDragging = true;
if (mCanThumbDetach) {
mIsThumbDetached = true;
diff --git a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
index 31468c5..e2ed65f 100644
--- a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
+++ b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
@@ -47,8 +47,7 @@
* By changing the WindowManagerProxy we can override the window insets information
**/
private IWindowManager changeWindowManagerInstance(DeviceEmulationData deviceData) {
- WindowManagerProxy.INSTANCE.initializeForTesting(
- new TestWindowManagerProxy(mContext, deviceData));
+ WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(deviceData));
return WindowManagerGlobal.getWindowManagerService();
}
@@ -57,8 +56,7 @@
WindowManagerProxy original = WindowManagerProxy.INSTANCE.get(mContext);
// Set up emulation
final int userId = UserHandle.myUserId();
- WindowManagerProxy.INSTANCE.initializeForTesting(
- new TestWindowManagerProxy(mContext, device));
+ WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(device));
IWindowManager wm = changeWindowManagerInstance(device);
// Change density twice to force display controller to reset its state
wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density / 2, userId);
diff --git a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
index cbea688..2d6bbcc 100644
--- a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
+++ b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
@@ -19,7 +19,6 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
-import android.view.Display;
import android.view.WindowInsets;
import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
@@ -32,17 +31,12 @@
private final DeviceEmulationData mDevice;
- public TestWindowManagerProxy(Context context, DeviceEmulationData device) {
+ public TestWindowManagerProxy(DeviceEmulationData device) {
super(true);
mDevice = device;
}
@Override
- public boolean isInternalDisplay(Display display) {
- return display.getDisplayId() == Display.DEFAULT_DISPLAY;
- }
-
- @Override
protected int getDimenByName(Resources res, String resName) {
Integer mock = mDevice.resourceOverrides.get(resName);
return mock != null ? mock : super.getDimenByName(res, resName);
@@ -54,27 +48,25 @@
}
@Override
- public CachedDisplayInfo getDisplayInfo(Context context, Display display) {
- int rotation = display.getRotation();
+ public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
+ int rotation = getRotation(displayInfoContext);
Point size = new Point(mDevice.width, mDevice.height);
RotationUtils.rotateSize(size, rotation);
Rect cutout = new Rect(mDevice.cutout);
RotationUtils.rotateRect(cutout, rotation);
- return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutout);
+ return new CachedDisplayInfo(size, rotation, cutout);
}
@Override
- public WindowBounds getRealBounds(Context windowContext, Display display,
- CachedDisplayInfo info) {
- return estimateInternalDisplayBounds(windowContext)
- .get(getDisplayId(display)).second[display.getRotation()];
+ public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
+ return estimateInternalDisplayBounds(displayInfoContext).get(
+ getDisplayInfo(displayInfoContext))[getDisplay(displayInfoContext).getRotation()];
}
@Override
public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
Rect outInsets) {
- outInsets.set(getRealBounds(context, context.getDisplay(),
- getDisplayInfo(context, context.getDisplay())).insets);
+ outInsets.set(getRealBounds(context, getDisplayInfo(context)).insets);
return oldInsets;
}
}