Merge "Fix Taskbar Edu accessibility anmimation" into main
This commit is contained in:
@@ -56,7 +56,6 @@ import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVIT
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
|
||||
import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
|
||||
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
|
||||
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
@@ -79,7 +78,6 @@ import android.app.role.RoleManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
@@ -94,7 +92,6 @@ import android.os.Looper;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.util.Pair;
|
||||
import android.util.Size;
|
||||
import android.view.CrossWindowBlurListeners;
|
||||
@@ -249,16 +246,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
// {@link TaskRestartedDuringLaunchListener}, and remove them on activity destroy.
|
||||
private final List<TaskRestartedDuringLaunchListener> mRegisteredTaskStackChangeListener =
|
||||
new ArrayList<>();
|
||||
private final ContentObserver mAnimationRemovalObserver = new ContentObserver(
|
||||
ORDERED_BG_EXECUTOR.getHandler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mAreAnimationsEnabled = Global.getFloat(mLauncher.getContentResolver(),
|
||||
Global.ANIMATOR_DURATION_SCALE, 1f) > 0
|
||||
|| Global.getFloat(mLauncher.getContentResolver(),
|
||||
Global.TRANSITION_ANIMATION_SCALE, 1f) > 0;
|
||||
}
|
||||
};
|
||||
|
||||
private DeviceProfile mDeviceProfile;
|
||||
|
||||
@@ -287,7 +274,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
// Pairs of window starting type and starting window background color for starting tasks
|
||||
// Will never be larger than MAX_NUM_TASKS
|
||||
private LinkedHashMap<Integer, Pair<Integer, Integer>> mTaskStartParams;
|
||||
private boolean mAreAnimationsEnabled = true;
|
||||
|
||||
private final Interpolator mOpeningXInterpolator;
|
||||
private final Interpolator mOpeningInterpolator;
|
||||
@@ -298,7 +284,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mDeviceProfile = mLauncher.getDeviceProfile();
|
||||
mBackAnimationController = new LauncherBackAnimationController(mLauncher, this);
|
||||
checkAndMonitorIfAnimationsAreEnabled();
|
||||
|
||||
Resources res = mLauncher.getResources();
|
||||
mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
|
||||
@@ -1220,8 +1205,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
unregisterRemoteTransitions();
|
||||
mLauncher.removeOnDeviceProfileChangeListener(this);
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
|
||||
ORDERED_BG_EXECUTOR.execute(() -> mLauncher.getContentResolver()
|
||||
.unregisterContentObserver(mAnimationRemovalObserver));
|
||||
if (BuildConfig.IS_STUDIO_BUILD && !mRegisteredTaskStackChangeListener.isEmpty()) {
|
||||
throw new IllegalStateException("Failed to run onEndCallback created from"
|
||||
+ " getActivityLaunchOptions()");
|
||||
@@ -1275,17 +1258,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndMonitorIfAnimationsAreEnabled() {
|
||||
ORDERED_BG_EXECUTOR.execute(() -> {
|
||||
mAnimationRemovalObserver.onChange(true);
|
||||
mLauncher.getContentResolver().registerContentObserver(Global.getUriFor(
|
||||
Global.ANIMATOR_DURATION_SCALE), false, mAnimationRemovalObserver);
|
||||
mLauncher.getContentResolver().registerContentObserver(Global.getUriFor(
|
||||
Global.TRANSITION_ANIMATION_SCALE), false, mAnimationRemovalObserver);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private boolean launcherIsATargetWithMode(RemoteAnimationTarget[] targets, int mode) {
|
||||
for (RemoteAnimationTarget target : targets) {
|
||||
if (target.mode == mode && target.taskInfo != null
|
||||
@@ -1421,7 +1393,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
(LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
|
||||
mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
|
||||
isTransluscent, fallbackBackgroundColor);
|
||||
} else if (launcherView != null && mAreAnimationsEnabled) {
|
||||
} else if (launcherView != null && !RemoveAnimationSettingsTracker.INSTANCE.get(
|
||||
mLauncher).isRemoveAnimationEnabled()) {
|
||||
floatingIconView = getFloatingIconView(mLauncher, launcherView, null,
|
||||
mLauncher.getTaskbarUIController() == null
|
||||
? null
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.core.view.updateLayoutParams
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.android.launcher3.LauncherPrefs
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.RemoveAnimationSettingsTracker
|
||||
import com.android.launcher3.Utilities
|
||||
import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
|
||||
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
|
||||
@@ -128,6 +129,26 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
activityContext.dragLayer.post { maybeShowSearchEdu() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off auto play of lottie animations if user has opted to remove animation else attaches
|
||||
* click listener to allow user to play or pause animations.
|
||||
*/
|
||||
fun handleEduAnimations(animationViews: List<LottieAnimationView>) {
|
||||
for (animationView in animationViews) {
|
||||
if (
|
||||
RemoveAnimationSettingsTracker.INSTANCE.get(animationView.context)
|
||||
.isRemoveAnimationEnabled()
|
||||
) {
|
||||
animationView.pauseAnimation()
|
||||
} else {
|
||||
animationView.setOnClickListener {
|
||||
if (animationView.isAnimating) animationView.pauseAnimation()
|
||||
else animationView.playAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
|
||||
fun maybeShowSwipeEdu() {
|
||||
if (
|
||||
@@ -145,7 +166,9 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
requireViewById(R.id.taskbar_edu_title),
|
||||
TypefaceUtils.FONT_FAMILY_HEADLINE_SMALL_EMPHASIZED,
|
||||
)
|
||||
requireViewById<LottieAnimationView>(R.id.swipe_animation).supportLightTheme()
|
||||
val swipeAnimation = requireViewById<LottieAnimationView>(R.id.swipe_animation)
|
||||
swipeAnimation.supportLightTheme()
|
||||
handleEduAnimations(listOf(swipeAnimation))
|
||||
show()
|
||||
}
|
||||
}
|
||||
@@ -174,6 +197,7 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
splitscreenAnim.supportLightTheme()
|
||||
suggestionsAnim.supportLightTheme()
|
||||
pinningAnim.supportLightTheme()
|
||||
handleEduAnimations(listOf(splitscreenAnim, suggestionsAnim, pinningAnim))
|
||||
if (DisplayController.isTransientTaskbar(activityContext)) {
|
||||
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
|
||||
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
|
||||
@@ -249,9 +273,6 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
|
||||
tooltip?.run {
|
||||
allowTouchDismissal = true
|
||||
requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
|
||||
.supportLightTheme()
|
||||
|
||||
TypefaceUtils.setTypeface(
|
||||
requireViewById(R.id.taskbar_edu_title),
|
||||
TypefaceUtils.FONT_FAMILY_HEADLINE_SMALL_EMPHASIZED,
|
||||
@@ -261,6 +282,10 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
TypefaceUtils.FONT_FAMILY_BODY_MEDIUM_BASELINE,
|
||||
)
|
||||
|
||||
val pinningAnim =
|
||||
requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
|
||||
pinningAnim.supportLightTheme()
|
||||
handleEduAnimations(listOf(pinningAnim))
|
||||
updateLayoutParams<BaseDragLayer.LayoutParams> {
|
||||
if (DisplayController.isTransientTaskbar(activityContext)) {
|
||||
bottomMargin += activityContext.deviceProfile.taskbarHeight
|
||||
@@ -304,7 +329,9 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
inflateTooltip(R.layout.taskbar_edu_search)
|
||||
tooltip?.run {
|
||||
allowTouchDismissal = true
|
||||
requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
|
||||
val searchEdu = requireViewById<LottieAnimationView>(R.id.search_edu_animation)
|
||||
searchEdu.supportLightTheme()
|
||||
handleEduAnimations(listOf(searchEdu))
|
||||
val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
|
||||
|
||||
TypefaceUtils.setTypeface(
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.app.animation.Interpolators.SCROLL;
|
||||
import static com.android.launcher3.RemoveAnimationSettingsTracker.WINDOW_ANIMATION_SCALE_URI;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.SCROLL_FINISHED_MESSAGE;
|
||||
@@ -33,7 +34,6 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
@@ -1756,8 +1756,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
if (FeatureFlags.IS_STUDIO_BUILD && !Utilities.isRunningInTestHarness()) {
|
||||
duration *= Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
Settings.Global.WINDOW_ANIMATION_SCALE, 1);
|
||||
duration *= RemoveAnimationSettingsTracker.INSTANCE.get(getContext()).getValue(
|
||||
WINDOW_ANIMATION_SCALE_URI);
|
||||
}
|
||||
|
||||
whichPage = validateNewPage(whichPage);
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3
|
||||
|
||||
import android.content.Context
|
||||
import android.database.ContentObserver
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.Settings
|
||||
import android.provider.Settings.Global.ANIMATOR_DURATION_SCALE
|
||||
import android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE
|
||||
import android.provider.Settings.Global.WINDOW_ANIMATION_SCALE
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Tracker Class for when user turns on/off remove animation setting. */
|
||||
@LauncherAppSingleton
|
||||
class RemoveAnimationSettingsTracker
|
||||
@Inject
|
||||
constructor(@ApplicationContext val context: Context, tracker: DaggerSingletonTracker) :
|
||||
ContentObserver(Handler(Looper.getMainLooper())) {
|
||||
|
||||
private val contentResolver = context.contentResolver
|
||||
|
||||
/** Caches the last seen value for registered keys. */
|
||||
private val cache: MutableMap<Uri, Float> = ConcurrentHashMap()
|
||||
|
||||
init {
|
||||
UI_HELPER_EXECUTOR.execute {
|
||||
contentResolver.registerContentObserver(WINDOW_ANIMATION_SCALE_URI, false, this)
|
||||
contentResolver.registerContentObserver(TRANSITION_ANIMATION_SCALE_URI, false, this)
|
||||
contentResolver.registerContentObserver(ANIMATOR_DURATION_SCALE_URI, false, this)
|
||||
}
|
||||
|
||||
tracker.addCloseable {
|
||||
UI_HELPER_EXECUTOR.execute { contentResolver.unregisterContentObserver(this) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for this classes key from the cache. If not in cache, will call
|
||||
* [updateValue] to fetch.
|
||||
*/
|
||||
fun getValue(uri: Uri): Float {
|
||||
return getValue(uri, 1f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for this classes key from the cache. If not in cache, will call
|
||||
* [getValueFromSettingsGlobal] to fetch.
|
||||
*/
|
||||
private fun getValue(uri: Uri, defaultValue: Float): Float {
|
||||
return cache.computeIfAbsent(uri) { getValueFromSettingsGlobal(uri, defaultValue) }
|
||||
}
|
||||
|
||||
/** Returns if user has opted into having no animation on their device. */
|
||||
fun isRemoveAnimationEnabled(): Boolean {
|
||||
return getValue(WINDOW_ANIMATION_SCALE_URI) == 0f &&
|
||||
getValue(TRANSITION_ANIMATION_SCALE_URI) == 0f &&
|
||||
getValue(ANIMATOR_DURATION_SCALE_URI) == 0f
|
||||
}
|
||||
|
||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
if (uri == null) return
|
||||
updateValue(uri)
|
||||
}
|
||||
|
||||
private fun getValueFromSettingsGlobal(uri: Uri, defaultValue: Float = 1f): Float {
|
||||
return Settings.Global.getFloat(contentResolver, uri.lastPathSegment, defaultValue)
|
||||
}
|
||||
|
||||
private fun updateValue(uri: Uri, defaultValue: Float = 1f) {
|
||||
val newValue = getValueFromSettingsGlobal(uri, defaultValue)
|
||||
cache[uri] = newValue
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE =
|
||||
DaggerSingletonObject(LauncherAppComponent::getRemoveAnimationSettingsTracker)
|
||||
@JvmField
|
||||
val WINDOW_ANIMATION_SCALE_URI: Uri = Settings.Global.getUriFor(WINDOW_ANIMATION_SCALE)
|
||||
@JvmField
|
||||
val TRANSITION_ANIMATION_SCALE_URI: Uri =
|
||||
Settings.Global.getUriFor(TRANSITION_ANIMATION_SCALE)
|
||||
@JvmField
|
||||
val ANIMATOR_DURATION_SCALE_URI: Uri = Settings.Global.getUriFor(ANIMATOR_DURATION_SCALE)
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
import com.android.launcher3.RemoveAnimationSettingsTracker;
|
||||
import com.android.launcher3.graphics.GridCustomizationsProxy;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.icons.LauncherIcons.IconPool;
|
||||
@@ -80,8 +81,8 @@ public interface LauncherBaseAppComponent {
|
||||
LockedUserState getLockedUserState();
|
||||
InvariantDeviceProfile getIDP();
|
||||
IconPool getIconPool();
|
||||
RemoveAnimationSettingsTracker getRemoveAnimationSettingsTracker();
|
||||
LauncherAppState getLauncherAppState();
|
||||
|
||||
GridCustomizationsProxy getGridCustomizationsProxy();
|
||||
|
||||
/** Builder for LauncherBaseAppComponent. */
|
||||
|
||||
Reference in New Issue
Block a user