fix: Android 14/15 crash

This commit is contained in:
Pun Butrach
2025-11-23 00:34:44 +07:00
parent d36845897b
commit edfd0baad6
1639 changed files with 146874 additions and 93622 deletions
@@ -20,14 +20,13 @@ import static android.animation.LayoutTransition.CHANGE_APPEARING;
import static android.animation.LayoutTransition.CHANGE_DISAPPEARING;
import static android.animation.LayoutTransition.DISAPPEARING;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.DesktopModeFlags.ENABLE_TASKBAR_OVERFLOW;
import static android.window.DesktopModeFlags.ENABLE_TASKBAR_RECENTS_LAYOUT_TRANSITION;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.BubbleTextView.LINE_INDICATOR_ANIM_DURATION;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Flags.taskbarOverflow;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
@@ -81,6 +80,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.TaskItemInfo;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
@@ -94,6 +94,7 @@ import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.SandboxContext;
import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SingleTask;
import com.android.systemui.shared.recents.model.Task;
@@ -136,11 +137,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private static final float ERROR_POSITION_IN_HOTSEAT_NOT_FOUND = -100;
private static final int TRANSITION_DELAY = 50;
private static final int TRANSITION_DEFAULT_DURATION = 500;
static final int TRANSITION_DEFAULT_DURATION = 500;
private static final int TRANSITION_FADE_IN_DURATION = 167;
private static final int TRANSITION_FADE_OUT_DURATION = 83;
private static final int APPEARING_LINE_INDICATOR_ANIM_DELAY =
TRANSITION_DEFAULT_DURATION - LINE_INDICATOR_ANIM_DURATION;
private final TaskbarActivityContext mActivity;
private @Nullable TaskbarDragLayerController mDragLayerController;
@@ -164,6 +163,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private final AnimatedFloat mTranslationXForBubbleBar = new AnimatedFloat(
this::updateTranslationXForBubbleBar);
private final TransitionEndBoundsChangedNotifier mTransitionEndBoundsChangedNotifier =
new TransitionEndBoundsChangedNotifier();
@Nullable
private Animator mTaskbarShiftXAnim;
@Nullable
@@ -224,24 +226,27 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private final float mTaskbarLeftRightMargin;
private final TaskbarRunningAppStateAnimationController mRunningStateController;
public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
mActivity = activity;
mTransientTaskbarDp = mActivity.getTransientTaskbarDeviceProfile();
mPersistentTaskbarDp = mActivity.getPersistentTaskbarDeviceProfile();
mTransientIconSize = mTransientTaskbarDp.taskbarIconSize;
mPersistentIconSize = mPersistentTaskbarDp.taskbarIconSize;
mTransientIconSize = mTransientTaskbarDp.getTaskbarProfile().getIconSize();
mPersistentIconSize = mPersistentTaskbarDp.getTaskbarProfile().getIconSize();
mTaskbarView = taskbarView;
mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, NUM_ALPHA_CHANNELS);
mTaskbarIconAlpha.setUpdateVisibility(true);
mModelCallbacks = TaskbarModelCallbacksFactory.newInstance(mActivity)
.create(mActivity, mTaskbarView);
mTaskbarBottomMargin = activity.getDeviceProfile().taskbarBottomMargin;
mTaskbarBottomMargin = activity.getDeviceProfile().getTaskbarProfile().getBottomMargin();
mStashedHandleHeight = activity.getResources()
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height);
mIsRtl = Utilities.isRtl(mTaskbarView.getResources());
mTaskbarLeftRightMargin = mActivity.getResources().getDimensionPixelSize(
R.dimen.transient_taskbar_padding);
mRunningStateController = new TaskbarRunningAppStateAnimationController(mActivity);
}
/**
@@ -262,9 +267,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create(
mActivity, mControllers, mTaskbarView));
// Pinning popup feature availability depends on taskbar controllers, wait for the
// controllers state initialization before evaluating the feature.
mControllers.runAfterInit(mTaskbarView::updatePinningPopupEventHandlers);
mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode()
? mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_phone_size)
: mActivity.getDeviceProfile().taskbarHeight;
: mActivity.getDeviceProfile().getTaskbarProfile().getHeight();
mTaskbarIconScaleForStash.updateValue(1f);
float pinningValue =
@@ -298,6 +306,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
}
/**
* Called whenever a new ui controller is set.
*/
public void onUiControllerChanged() {
// Pinning availability may depend on UI state when home has "locked" pinned taskbar.
mTaskbarView.updatePinningPopupEventHandlers();
}
/** Adjusts start aligned taskbar layout accordingly to the bubble bar position. */
@Override
public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
@@ -395,6 +411,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
mRunningStateController.onDestroy();
}
/**
@@ -412,6 +429,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
return mTaskbarIconAlpha;
}
/** Creates a ModelWriter for updating model properties */
public ModelWriter getModelWriter() {
return LauncherAppState.getInstance(mActivity).getModel()
.getWriter(false, mActivity.getCellPosMapper(), mModelCallbacks);
}
/**
* Should be called when the recents button is disabled, so we can hide Taskbar icons as well.
*/
@@ -563,7 +586,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
sizeDiffTranslationRange *= -1;
}
if (mActivity.isThreeButtonNav()) {
if (!mTaskbarView.canTransitionToTransientTaskbar()) {
mTaskbarView.getAllAppsButtonContainer()
.setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
return;
@@ -665,17 +688,19 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
// finally placing the icon in the middle of new taskbar background height.
if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
float transY =
mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
mTransientTaskbarDp.getTaskbarProfile().getBottomMargin() + (
mTransientTaskbarDp.getTaskbarProfile().getHeight()
- mTaskbarView.getTransientTaskbarIconLayoutBounds().bottom)
- (mPersistentTaskbarDp.taskbarHeight
- mTransientTaskbarDp.taskbarIconSize) / 2f;
- (mPersistentTaskbarDp.getTaskbarProfile().getHeight()
- mTransientTaskbarDp.getTaskbarProfile().getIconSize()) / 2f;
taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
} else {
float transY =
-mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
-mTransientTaskbarDp.getTaskbarProfile().getBottomMargin() + (
mPersistentTaskbarDp.getTaskbarProfile().getHeight()
- mTaskbarView.getTransientTaskbarIconLayoutBounds().bottom)
- (mTransientTaskbarDp.taskbarHeight
- mTransientTaskbarDp.taskbarIconSize) / 2f;
- (mTransientTaskbarDp.getTaskbarProfile().getHeight()
- mTransientTaskbarDp.getTaskbarProfile().getIconSize()) / 2f;
taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
}
return taskbarIconTranslationYForPinningValue;
@@ -748,33 +773,41 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
private boolean shouldUpdateIconContentDescription(BubbleTextView btv) {
boolean isInDesktopMode = mControllers.taskbarDesktopModeController.isInDesktopMode(
DEFAULT_DISPLAY);
boolean isInDesktopMode =
mControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar(
DEFAULT_DISPLAY);
boolean isAllAppsButton = btv instanceof TaskbarAllAppsButtonContainer;
boolean isDividerButton = btv instanceof TaskbarDividerContainer;
return isInDesktopMode && !isAllAppsButton && !isDividerButton;
}
/**
* @return A set of Task ids of running apps that are pinned in the taskbar.
* @return A set of Task ids shown in the taskbar - includes task ID for running tasks of pinned
* apps, and standalone running tasks.
*/
protected Set<Integer> getTaskIdsForPinnedApps() {
if (!taskbarOverflow()) {
protected Set<Integer> getShownTaskIds() {
if (!ENABLE_TASKBAR_OVERFLOW.isTrue()) {
return Collections.emptySet();
}
Set<Integer> pinnedAppsWithTasks = new HashSet<>();
Set<Integer> shownTasks = new HashSet<>();
for (View iconView : getIconViews()) {
if (iconView instanceof BubbleTextView btv
&& btv.getTag() instanceof TaskItemInfo itemInfo) {
pinnedAppsWithTasks.add(itemInfo.getTaskId());
if (iconView instanceof BubbleTextView btv) {
if (btv.getTag() instanceof TaskItemInfo itemInfo) {
shownTasks.add(itemInfo.getTaskId());
} else if (btv.getTag() instanceof SingleTask task) {
shownTasks.add(task.getTask().getKey().id);
}
}
}
return pinnedAppsWithTasks;
return shownTasks;
}
private void updateRunningState(BubbleTextView btv) {
btv.updateRunningState(getRunningAppState(btv), mTaskbarView.getLayoutTransition() != null);
mRunningStateController.updateRunningState(
btv,
getRunningAppState(btv),
/* animate = */ mTaskbarView.getLayoutTransition() != null);
}
private BubbleTextView.RunningAppState getRunningAppState(BubbleTextView btv) {
@@ -875,6 +908,16 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
as.play(reveal);
}
void notifyIconLayoutBoundsChanged() {
final LayoutTransition layoutTransition = mTaskbarView.getLayoutTransition();
if (layoutTransition != null && layoutTransition.isRunning()) {
// Defers notify until after transitions finish.
mTransitionEndBoundsChangedNotifier.mIsCanceled = false;
} else {
mControllers.uiController.onIconLayoutBoundsChanged();
}
}
/**
* Sets the Taskbar icon alignment relative to Launcher hotseat icons
* @param alignmentRatio [0, 1]
@@ -898,6 +941,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
mIsIconAlignedWithHotseat = isIconAlignedWithHotseat;
mIsStashed = isStashed;
final LayoutTransition layoutTransition = mTaskbarView.getLayoutTransition();
if (layoutTransition != null && layoutTransition.isRunning()) {
mTransitionEndBoundsChangedNotifier.mIsCanceled = true;
layoutTransition.cancel();
}
mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
}
mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
@@ -940,12 +989,16 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
boolean isTransientTaskbar = mActivity.isTransientTaskbar();
float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.taskbarIconSize;
float scaleUp = ((float) launcherDp.iconSizePx)
/ taskbarDp.getTaskbarProfile().getIconSize();
int borderSpacing = launcherDp.hotseatBorderSpace;
int hotseatCellSize = DeviceProfile.calculateCellWidth(
launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right,
launcherDp.getDeviceProperties().getAvailableWidthPx()
- hotseatPadding.left
- hotseatPadding.right,
borderSpacing,
launcherDp.numShownHotseatIcons);
launcherDp.numShownHotseatIcons
);
boolean isToHome = mControllers.uiController.isIconAlignedWithHotseat();
boolean isDeviceLocked = mControllers.taskbarStashController.isDeviceLocked();
@@ -970,13 +1023,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
}
int collapsedHeight = mActivity.getDefaultTaskbarWindowSize();
int expandedHeight = Math.max(collapsedHeight, taskbarDp.taskbarHeight + offsetY);
int expandedHeight = Math.max(collapsedHeight,
taskbarDp.getTaskbarProfile().getHeight() + offsetY);
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowSize(
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
mTaskbarBottomMargin = isTransientTaskbar
? mTransientTaskbarDp.taskbarBottomMargin
: mPersistentTaskbarDp.taskbarBottomMargin;
? mTransientTaskbarDp.getTaskbarProfile().getBottomMargin()
: mPersistentTaskbarDp.getTaskbarProfile().getBottomMargin();
int firstRecentTaskIndex = -1;
int hotseatNavBarTranslationX = 0;
@@ -986,12 +1040,17 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
hotseatNavBarTranslationX = taskbarDp
.getHotseatTranslationXForNavBar(mActivity, isBubblesOnLeft);
}
int ignoreCount = mTaskbarView.getIgnoreTaskbarIconCount();
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
boolean isTaskbarOverflowView = child == mTaskbarView.getTaskbarOverflowView();
boolean isRecentTask = child.getTag() instanceof GroupTask;
boolean isRtl = Utilities.isRtl(child.getResources());
// TODO(b/343522351): show recents on the home screen.
final boolean isRecentsInHotseat = false;
if (!mIsHotseatIconOnTopWhenAligned) {
@@ -1020,11 +1079,21 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
? Interpolators.clampToProgress(LINEAR, 0f, 0.17f)
: Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f));
}
} else if (((!isRtl && mTaskbarView.getChildCount() - i <= ignoreCount)
|| (isRtl && i < ignoreCount))
&& mIsHotseatIconOnTopWhenAligned
&& !(child instanceof IconButtonView)) {
setter.addFloat(child, VIEW_ALPHA, 0f, 1f,
isToHome
? Interpolators.clampToProgress(LINEAR, 0f, 0.35f)
: mActivity.getDeviceProfile().isQsbInline
? Interpolators.clampToProgress(LINEAR, 0f, 1f)
: Interpolators.clampToProgress(LINEAR, 0.84f, 1f));
setter.addOnFrameListener(animator -> AlphaUpdateListener.updateVisibility(child));
}
if (child == mTaskbarView.getQsb()) {
boolean isRtl = Utilities.isRtl(child.getResources());
float hotseatIconCenter = isRtl
? launcherDp.widthPx - hotseatPadding.right + borderSpacing
? launcherDp.getDeviceProperties().getWidthPx() - hotseatPadding.right + borderSpacing
+ launcherDp.hotseatQsbWidth / 2f
: hotseatPadding.left - borderSpacing - launcherDp.hotseatQsbWidth / 2f;
if (taskbarDp.isQsbInline) {
@@ -1036,9 +1105,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
INDEX_TASKBAR_PINNING_ANIM).getValue();
}
float halfQsbIconWidthDiff =
(launcherDp.hotseatQsbWidth - taskbarDp.taskbarIconSize) / 2f;
float scale = ((float) taskbarDp.taskbarIconSize)
/ launcherDp.hotseatQsbVisualHeight;
(launcherDp.hotseatQsbWidth - taskbarDp.getTaskbarProfile().getIconSize())
/ 2f;
float scale = ((float) taskbarDp.getTaskbarProfile().getIconSize())
/ launcherDp.getHotseatProfile().getQsbVisualHeight();
setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator);
float fromX = isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff;
@@ -1185,7 +1255,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
? R.dimen.taskbar_phone_size
: R.dimen.taskbar_stashed_size);
} else {
taskbarWindowSize = deviceProfile.taskbarHeight + deviceProfile.getTaskbarOffsetY();
taskbarWindowSize = mActivity.getDefaultTaskbarWindowSize();
}
if (mBubbleControllers != null) {
int bubbleBarMaxHeight = mBubbleControllers.bubbleBarViewController
.getBubbleBarWithFlyoutMaximumHeight();
taskbarWindowSize = Math.max(taskbarWindowSize, bubbleBarMaxHeight);
}
mActivity.setTaskbarWindowSize(taskbarWindowSize);
mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
@@ -1237,10 +1312,6 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
view.setAlpha(0f);
view.setScaleX(0f);
view.setScaleY(0f);
if (view instanceof BubbleTextView btv) {
// Defer so that app is mostly scaled in before showing indicator.
btv.setLineIndicatorAnimStartDelay(APPEARING_LINE_INDICATOR_ANIM_DELAY);
}
} else if (type == DISAPPEARING && view instanceof BubbleTextView btv) {
// Running state updates happen after removing this view, so update it here.
updateRunningState(btv);
@@ -1250,11 +1321,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
@Override
public void endTransition(
LayoutTransition transition, ViewGroup container, View view, int type) {
if (type == APPEARING && view instanceof BubbleTextView btv) {
btv.setLineIndicatorAnimStartDelay(0);
}
// Do nothing.
}
});
layoutTransition.addTransitionListener(mTransitionEndBoundsChangedNotifier);
// Appearing.
AnimatorSet appearingSet = new AnimatorSet();
@@ -1313,6 +1383,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
return layoutTransition;
}
public boolean isTaskbarInMinimalState() {
return mTaskbarView.isTaskbarInMinimalState();
}
/**
* To be called when the given Task is updated, so that we can tell TaskbarView to also update.
* @param task The Task whose e.g. icon changed.
@@ -1334,7 +1408,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarViewController:");
pw.println(prefix + "\tignoreTaskbarIconCount=" + mTaskbarView.getIgnoreTaskbarIconCount());
mTaskbarIconAlpha.dump(
prefix + "\t",
pw,
@@ -1357,4 +1431,22 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
animator.setInterpolator(EMPHASIZED);
return animator;
}
private class TransitionEndBoundsChangedNotifier implements TransitionListener {
private boolean mIsCanceled;
@Override
public void startTransition(
LayoutTransition transition, ViewGroup container, View view, int type) {
// Do nothing.
}
@Override
public void endTransition(
LayoutTransition transition, ViewGroup container, View view, int type) {
if (!transition.isRunning() && !mIsCanceled) {
mControllers.uiController.onIconLayoutBoundsChanged();
}
}
}
}