Snap for 7487213 from dc01385cc2 to sc-v2-release

Change-Id: I54ed501e33a49c6d4b3fad9762f0b8a97144c8e1
This commit is contained in:
Android Build Coastguard Worker
2021-06-24 01:13:59 +00:00
71 changed files with 1944 additions and 4738 deletions
+11
View File
@@ -573,4 +573,15 @@
column="42"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#setColorResources`"
errorLine1=" setColorResources(mWallpaperColorResources);"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
line="528"
column="17"/>
</issue>
</issues>
@@ -26,6 +26,7 @@ message ExtendedContainers {
oneof Container{
DeviceSearchResultContainer device_search_result_container = 1;
CorrectedDeviceSearchResultContainer corrected_device_search_result_container = 2;
}
}
@@ -33,3 +34,9 @@ message ExtendedContainers {
message DeviceSearchResultContainer{
optional int32 query_length = 1;
}
// Represents on-device search result container with results from spell-corrected query.
message CorrectedDeviceSearchResultContainer{
optional int32 query_length = 1;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -423,7 +423,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
ActivityOptionsWrapper activityOptions =
mAppTransitionManager.hasControlRemoteAppTransitionPermission()
? mAppTransitionManager.getActivityLaunchOptions(this, v)
? mAppTransitionManager.getActivityLaunchOptions(v)
: super.getActivityLaunchOptions(v, item);
if (mLastTouchUpTime > 0) {
ActivityOptionsCompat.setLauncherSourceInfo(
@@ -36,26 +36,48 @@ import androidx.annotation.UiThread;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.lang.ref.WeakReference;
/**
* This class is needed to wrap any animation runner that is a part of the
* RemoteAnimationDefinition:
* - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is
* created, which in turn registers a new definition
* - When the definition is registered, window manager retains a strong binder reference to the
* runner passed in
* - If the Launcher activity is recreated, the new definition registered will replace the old
* reference in the system's activity record, but until the system server is GC'd, the binder
* reference will still exist, which references the runner in the Launcher process, which
* references the (old) Launcher activity through this class
*
* Instead we make the runner provided to the definition static only holding a weak reference to
* the runner implementation. When this animation manager is destroyed, we remove the Launcher
* reference to the runner, leaving only the weak ref from the runner.
*/
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
private static final RemoteAnimationFactory DEFAULT_FACTORY =
(transit, appTargets, wallpaperTargets, nonAppTargets, result) ->
result.setAnimation(null, null);
private final Handler mHandler;
private final boolean mStartAtFrontOfQueue;
private final WeakReference<RemoteAnimationFactory> mFactory;
private AnimationResult mAnimationResult;
/**
* @param startAtFrontOfQueue If true, the animation start will be posted at the front of the
* queue to minimize latency.
*/
public LauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue) {
public LauncherAnimationRunner(Handler handler, RemoteAnimationFactory factory,
boolean startAtFrontOfQueue) {
mHandler = handler;
mFactory = new WeakReference<>(factory);
mStartAtFrontOfQueue = startAtFrontOfQueue;
}
public Handler getHandler() {
return mHandler;
}
// Called only in S+ platform
@BinderThread
public void onAnimationStart(
@@ -67,7 +89,7 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
getFactory().onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
mAnimationResult);
};
if (mStartAtFrontOfQueue) {
@@ -92,17 +114,11 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
onAnimationStart(appTargets, new RemoteAnimationTargetCompat[0], runnable);
}
/**
* Called on the UI thread when the animation targets are received. The implementation must
* call {@link AnimationResult#setAnimation} with the target animation to be run.
*/
@UiThread
public abstract void onCreateAnimation(
int transit,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
AnimationResult result);
private RemoteAnimationFactory getFactory() {
RemoteAnimationFactory factory = mFactory.get();
return factory != null ? factory : DEFAULT_FACTORY;
}
@UiThread
private void finishExistingAnimation() {
@@ -118,7 +134,10 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
@BinderThread
@Override
public void onAnimationCancelled() {
postAsyncCallback(mHandler, this::finishExistingAnimation);
postAsyncCallback(mHandler, () -> {
finishExistingAnimation();
getFactory().onAnimationCancelled();
});
}
public static final class AnimationResult {
@@ -153,7 +172,6 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
@UiThread
public void setAnimation(AnimatorSet animation, Context context) {
setAnimation(animation, context, null, true);
}
/**
@@ -198,4 +216,28 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
}
}
}
/**
* Used with LauncherAnimationRunner as an interface for the runner to call back to the
* implementation.
*/
@FunctionalInterface
public interface RemoteAnimationFactory {
/**
* Called on the UI thread when the animation targets are received. The implementation must
* call {@link AnimationResult#setAnimation} with the target animation to be run.
*/
void onCreateAnimation(int transit,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result);
/**
* Called when the animation is cancelled. This can happen with or without
* the create being called.
*/
default void onAnimationCancelled() { }
}
}
@@ -79,6 +79,7 @@ import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -197,11 +198,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private RemoteAnimationProvider mRemoteAnimationProvider;
// Strong refs to runners which are cleared when the launcher activity is destroyed
private WrappedAnimationRunnerImpl mWallpaperOpenRunner;
private WrappedAnimationRunnerImpl mAppLaunchRunner;
private WrappedAnimationRunnerImpl mKeyguardGoingAwayRunner;
private RemoteAnimationFactory mWallpaperOpenRunner;
private RemoteAnimationFactory mAppLaunchRunner;
private RemoteAnimationFactory mKeyguardGoingAwayRunner;
private WrappedAnimationRunnerImpl mWallpaperOpenTransitionRunner;
private RemoteAnimationFactory mWallpaperOpenTransitionRunner;
private RemoteTransitionCompat mLauncherOpenTransition;
private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
@@ -257,11 +258,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
* @return ActivityOptions with remote animations that controls how the window of the opening
* targets are displayed.
*/
public ActivityOptionsWrapper getActivityLaunchOptions(Launcher launcher, View v) {
public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
RunnableList onEndCallback = new RunnableList();
mAppLaunchRunner = new AppLaunchAnimationRunner(mHandler, v, onEndCallback);
RemoteAnimationRunnerCompat runner = new WrappedLauncherAnimationRunner<>(
mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
// Note that this duration is a guess as we do not know if the animation will be a
@@ -1006,7 +1007,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapterCompat(
new WrappedLauncherAnimationRunner<>(mHandler, mWallpaperOpenRunner,
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
@@ -1015,7 +1016,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
definition.addRemoteAnimation(
WindowManagerWrapper.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
new RemoteAnimationAdapterCompat(
new WrappedLauncherAnimationRunner<>(
new LauncherAnimationRunner(
mHandler, mKeyguardGoingAwayRunner,
true /* startAtFrontOfQueue */),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
@@ -1035,7 +1036,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
if (hasControlRemoteAppTransitionPermission()) {
mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
new WrappedLauncherAnimationRunner<>(mHandler, mWallpaperOpenTransitionRunner,
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */));
mLauncherOpenTransition.addHomeOpenCheck();
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
@@ -1093,7 +1094,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
* @return Runner that plays when user goes to Launcher
* ie. pressing home, swiping up from nav bar.
*/
WrappedAnimationRunnerImpl createWallpaperOpenRunner(boolean fromUnlock) {
RemoteAnimationFactory createWallpaperOpenRunner(boolean fromUnlock) {
return new WallpaperOpenLauncherAnimationRunner(mHandler, fromUnlock);
}
@@ -1243,7 +1244,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
protected class WallpaperOpenLauncherAnimationRunner implements WrappedAnimationRunnerImpl {
protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory {
private final Handler mHandler;
private final boolean mFromUnlock;
@@ -1331,17 +1332,12 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
/**
* Remote animation runner for animation to launch an app.
*/
private class AppLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
private class AppLaunchAnimationRunner implements RemoteAnimationFactory {
private static final String TRANSITION_LAUNCH_FROM_RECENTS = "transition:LaunchFromRecents";
private static final String TRANSITION_LAUNCH_FROM_ICON = "transition:LaunchFromIcon";
private final Handler mHandler;
private final View mV;
private final RunnableList mOnEndCallback;
AppLaunchAnimationRunner(Handler handler, View v, RunnableList onEndCallback) {
mHandler = handler;
AppLaunchAnimationRunner(View v, RunnableList onEndCallback) {
mV = v;
mOnEndCallback = onEndCallback;
}
@@ -1385,6 +1381,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
skipFirstFrame);
}
@Override
public void onAnimationCancelled() {
mOnEndCallback.executeAllAndDestroy();
}
}
/**
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the
* implementation.
*/
public interface WrappedAnimationRunnerImpl {
void onCreateAnimation(int transit,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result);
}
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.os.Handler;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.lang.ref.WeakReference;
/**
* This class is needed to wrap any animation runner that is a part of the
* RemoteAnimationDefinition:
* - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is
* created, which in turn registers a new definition
* - When the definition is registered, window manager retains a strong binder reference to the
* runner passed in
* - If the Launcher activity is recreated, the new definition registered will replace the old
* reference in the system's activity record, but until the system server is GC'd, the binder
* reference will still exist, which references the runner in the Launcher process, which
* references the (old) Launcher activity through this class
*
* Instead we make the runner provided to the definition static only holding a weak reference to
* the runner implementation. When this animation manager is destroyed, we remove the Launcher
* reference to the runner, leaving only the weak ref from the runner.
*/
public class WrappedLauncherAnimationRunner<R extends WrappedAnimationRunnerImpl>
extends LauncherAnimationRunner {
private WeakReference<R> mImpl;
public WrappedLauncherAnimationRunner(
Handler handler, R animationRunnerImpl, boolean startAtFrontOfQueue) {
super(handler, startAtFrontOfQueue);
mImpl = new WeakReference<>(animationRunnerImpl);
}
@Override
public void onCreateAnimation(int transit,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
AnimationResult result) {
R animationRunnerImpl = mImpl.get();
if (animationRunnerImpl != null) {
animationRunnerImpl.onCreateAnimation(transit, appTargets, wallpaperTargets,
nonAppTargets, result);
} else {
result.setAnimation(null, null);
}
}
}
@@ -25,6 +25,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.os.IBinder;
import android.util.FloatProperty;
import android.view.CrossWindowBlurListeners;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewRootImpl;
@@ -41,6 +42,8 @@ import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.WallpaperManagerCompat;
import java.util.function.Consumer;
/**
* Controls blur and wallpaper zoom, for the Launcher surface only.
*/
@@ -96,11 +99,17 @@ public class DepthController implements StateHandler<LauncherState>,
}
};
private final Consumer<Boolean> mCrossWindowBlurListener = (enabled) -> {
mCrossWindowBlursEnabled = enabled;
dispatchTransactionSurface();
};
private final Launcher mLauncher;
/**
* Blur radius when completely zoomed out, in pixels.
*/
private int mMaxBlurRadius;
private boolean mCrossWindowBlursEnabled;
private WallpaperManagerCompat mWallpaperManager;
private SurfaceControl mSurface;
/**
@@ -123,6 +132,7 @@ public class DepthController implements StateHandler<LauncherState>,
mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius);
mWallpaperManager = new WallpaperManagerCompat(mLauncher);
}
if (mLauncher.getRootView() != null && mOnAttachListener == null) {
mOnAttachListener = new View.OnAttachStateChangeListener() {
@Override
@@ -132,13 +142,20 @@ public class DepthController implements StateHandler<LauncherState>,
if (windowToken != null) {
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
}
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
mCrossWindowBlurListener);
}
@Override
public void onViewDetachedFromWindow(View view) {
CrossWindowBlurListeners.getInstance().removeListener(mCrossWindowBlurListener);
}
};
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
if (mLauncher.getRootView().isAttachedToWindow()) {
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
mCrossWindowBlurListener);
}
}
}
@@ -220,7 +237,8 @@ public class DepthController implements StateHandler<LauncherState>,
boolean isOverview = mLauncher.isInState(LauncherState.OVERVIEW);
boolean opaque = mLauncher.getScrimView().isFullyOpaque() && !isOverview;
int blur = opaque || isOverview ? 0 : (int) (mDepth * mMaxBlurRadius);
int blur = opaque || isOverview || !mCrossWindowBlursEnabled
? 0 : (int) (mDepth * mMaxBlurRadius);
new SurfaceControl.Transaction()
.setBackgroundBlurRadius(mSurface, blur)
.setOpaque(mSurface, opaque)
@@ -26,6 +26,7 @@ import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.RemoteViews;
import android.window.SplashScreen;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
@@ -56,7 +57,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
}
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
.getActivityLaunchOptions(mLauncher, hostView);
.getActivityLaunchOptions(hostView);
if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
// In the event this pending intent eventually launches an activity, i.e. a trampoline,
// use the Quickstep transition animation.
@@ -70,6 +71,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
}
}
activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
Object itemInfo = hostView.getTag();
if (itemInfo instanceof ItemInfo) {
mLauncher.addLaunchCookie((ItemInfo) itemInfo, activityOptions.options);
@@ -49,9 +49,8 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.R;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
@@ -109,7 +108,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
private StateManager<RecentsState> mStateManager;
// Strong refs to runners which are cleared when the activity is destroyed
private WrappedAnimationRunnerImpl mActivityLaunchAnimationRunner;
private RemoteAnimationFactory mActivityLaunchAnimationRunner;
/**
* Init drag layer and overview panel views.
@@ -206,19 +205,25 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
final TaskView taskView = (TaskView) v;
RunnableList onEndCallback = new RunnableList();
mActivityLaunchAnimationRunner = (int transit,
RemoteAnimationTargetCompat[] appTargets,
mActivityLaunchAnimationRunner = new RemoteAnimationFactory() {
@Override
public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
AnimationResult result) -> {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets, nonAppTargets);
anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy,
true /* skipFirstFrame */);
RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets, nonAppTargets);
anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy,
true /* skipFirstFrame */);
}
@Override
public void onAnimationCancelled() {
onEndCallback.executeAllAndDestroy();
}
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>(
final LauncherAnimationRunner wrapper = new LauncherAnimationRunner(
mUiHandler, mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */);
RemoteAnimationAdapterCompat adapterCompat = new RemoteAnimationAdapterCompat(
wrapper, RECENTS_LAUNCH_DURATION,
@@ -263,6 +268,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
mFallbackRecentsView.updateLocusId();
}
@Override
@@ -271,6 +277,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
mFallbackRecentsView.updateLocusId();
}
@Override
@@ -362,34 +369,37 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
}
private void startHomeInternal() {
WrappedLauncherAnimationRunner runner = new WrappedLauncherAnimationRunner(
getMainThreadHandler(), this::onCreateAnimationToHome, true);
LauncherAnimationRunner runner = new LauncherAnimationRunner(
getMainThreadHandler(), mAnimationToHomeFactory, true);
RemoteAnimationAdapterCompat adapterCompat =
new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
startActivity(createHomeIntent(),
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
}
private void onCreateAnimationToHome(
int transit, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
AnimatorPlaybackController controller = getStateManager()
.createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
controller.dispatchOnStart();
private final RemoteAnimationFactory mAnimationToHomeFactory =
new RemoteAnimationFactory() {
@Override
public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
AnimatorPlaybackController controller = getStateManager()
.createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
controller.dispatchOnStart();
RemoteAnimationTargets targets = new RemoteAnimationTargets(
appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
for (RemoteAnimationTargetCompat app : targets.apps) {
new Transaction().setAlpha(app.leash.getSurfaceControl(), 1).apply();
RemoteAnimationTargets targets = new RemoteAnimationTargets(
appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
for (RemoteAnimationTargetCompat app : targets.apps) {
new Transaction().setAlpha(app.leash.getSurfaceControl(), 1).apply();
}
AnimatorSet anim = new AnimatorSet();
anim.play(controller.getAnimationPlayer());
anim.setDuration(HOME_APPEAR_DURATION);
result.setAnimation(anim, RecentsActivity.this,
() -> getStateManager().goToState(RecentsState.HOME, false),
true /* skipFirstFrame */);
}
AnimatorSet anim = new AnimatorSet();
anim.play(controller.getAnimationPlayer());
anim.setDuration(HOME_APPEAR_DURATION);
result.setAnimation(anim, this,
() -> getStateManager().goToState(RecentsState.HOME, false),
true /* skipFirstFrame */);
}
};
@Override
protected void collectStateHandlers(List<StateHandler> out) {
@@ -29,12 +29,8 @@ public class BackGestureTutorialFragment extends TutorialFragment {
@Override
Integer getFeedbackVideoResId(boolean forDarkMode) {
return mTutorialType == TutorialType.RIGHT_EDGE_BACK_NAVIGATION
? (forDarkMode
? R.drawable.gesture_tutorial_motion_back_right_dark_mode
: R.drawable.gesture_tutorial_motion_back_right_light_mode)
: (forDarkMode
? R.drawable.gesture_tutorial_motion_back_left_dark_mode
: R.drawable.gesture_tutorial_motion_back_left_light_mode);
? R.drawable.gesture_tutorial_motion_back_right
: R.drawable.gesture_tutorial_motion_back_left;
}
@Nullable
@@ -151,6 +151,7 @@ public class StatsLogCompatManager extends StatsLogManager {
private Optional<ToState> mToState = Optional.empty();
private Optional<String> mEditText = Optional.empty();
private SliceItem mSliceItem;
private LauncherAtom.Slice mSlice;
StatsCompatLogger(Context context) {
mContext = context;
@@ -193,7 +194,7 @@ public class StatsLogCompatManager extends StatsLogManager {
@Override
public StatsLogger withContainerInfo(ContainerInfo containerInfo) {
checkState(mItemInfo == DEFAULT_ITEM_INFO,
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
this.mContainerInfo = Optional.of(containerInfo);
return this;
}
@@ -218,9 +219,21 @@ public class StatsLogCompatManager extends StatsLogManager {
@Override
public StatsLogger withSliceItem(@NonNull SliceItem sliceItem) {
checkState(mItemInfo == DEFAULT_ITEM_INFO && mSlice == null,
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one"
+ " of them.");
this.mSliceItem = checkNotNull(sliceItem, "expected valid sliceItem but received null");
checkState(mItemInfo == DEFAULT_ITEM_INFO,
"ItemInfo and SliceItem are mutual exclusive; cannot log both.");
return this;
}
@Override
public StatsLogger withSlice(LauncherAtom.Slice slice) {
checkState(mItemInfo == DEFAULT_ITEM_INFO && mSliceItem == null,
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one"
+ " of them.");
checkNotNull(slice, "expected valid slice but received null");
checkNotNull(slice.getUri(), "expected valid slice uri but received null");
this.mSlice = slice;
return this;
}
@@ -231,13 +244,16 @@ public class StatsLogCompatManager extends StatsLogManager {
}
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mSliceItem != null) {
if (mSlice == null && mSliceItem != null) {
mSlice = LauncherAtom.Slice.newBuilder().setUri(
mSliceItem.getSlice().getUri().toString()).build();
}
if (mSlice != null) {
Executors.MODEL_EXECUTOR.execute(
() -> {
LauncherAtom.ItemInfo.Builder itemInfoBuilder =
LauncherAtom.ItemInfo.newBuilder().setSlice(
LauncherAtom.Slice.newBuilder().setUri(
mSliceItem.getSlice().getUri().toString()));
LauncherAtom.ItemInfo.newBuilder().setSlice(mSlice);
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
write(event, applyOverwrites(itemInfoBuilder.build()));
});
@@ -21,15 +21,14 @@ import android.content.Context;
import android.os.Handler;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public abstract class RemoteAnimationProvider {
WrappedAnimationRunnerImpl mAnimationRunner;
RemoteAnimationFactory mAnimationRunner;
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
@@ -37,7 +36,7 @@ public abstract class RemoteAnimationProvider {
ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
mAnimationRunner = (transit, appTargets, wallpaperTargets, nonApps, result) ->
result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context);
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner(
final LauncherAnimationRunner wrapper = new LauncherAnimationRunner(
handler, mAnimationRunner, false /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(wrapper, duration, 0));
@@ -41,9 +41,8 @@ import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.R;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
@@ -101,14 +100,14 @@ public class SplitSelectStateController {
return;
}
// Assume initial mInitialTaskId is for top/left part of screen
WrappedAnimationRunnerImpl initialSplitRunnerWrapped = new SplitLaunchAnimationRunner(
RemoteAnimationFactory initialSplitRunnerWrapped = new SplitLaunchAnimationRunner(
mInitialTaskView, 0);
WrappedAnimationRunnerImpl secondarySplitRunnerWrapped = new SplitLaunchAnimationRunner(
RemoteAnimationFactory secondarySplitRunnerWrapped = new SplitLaunchAnimationRunner(
taskView, 1);
RemoteAnimationRunnerCompat initialSplitRunner = new WrappedLauncherAnimationRunner(
RemoteAnimationRunnerCompat initialSplitRunner = new LauncherAnimationRunner(
new Handler(Looper.getMainLooper()), initialSplitRunnerWrapped,
true /* startAtFrontOfQueue */);
RemoteAnimationRunnerCompat secondarySplitRunner = new WrappedLauncherAnimationRunner(
RemoteAnimationRunnerCompat secondarySplitRunner = new LauncherAnimationRunner(
new Handler(Looper.getMainLooper()), secondarySplitRunnerWrapped,
true /* startAtFrontOfQueue */);
ActivityOptions initialOptions = ActivityOptionsCompat.makeRemoteAnimation(
@@ -192,7 +191,7 @@ public class SplitSelectStateController {
* LEGACY
* Remote animation runner for animation to launch an app.
*/
private class SplitLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
private class SplitLaunchAnimationRunner implements RemoteAnimationFactory {
private final TaskView mV;
private final int mTargetState;
@@ -62,6 +62,7 @@ import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.LocusId;
import android.content.res.Configuration;
import android.graphics.BlendMode;
import android.graphics.Canvas;
@@ -74,6 +75,7 @@ import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.Layout;
import android.text.StaticLayout;
@@ -883,7 +885,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finishRecentsAnimation(true /* toRecents */, null);
finishRecentsAnimation(false /* toRecents */, null);
}
});
} else {
@@ -952,6 +954,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
cancelSplitSelect(false);
}
}
updateLocusId();
}
/**
@@ -2421,12 +2424,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> {
UI_HELPER_EXECUTOR.getHandler().postDelayed(() ->
ActivityManagerWrapper.getInstance().removeTask(
dismissedTaskId), REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
});
if (LIVE_TILE.get() && dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> removeTaskInternal(dismissedTaskId));
} else {
removeTaskInternal(dismissedTaskId);
}
mActivity.getStatsLogManager().logger()
.withItemInfo(dismissedTaskView.getItemInfo())
.log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
@@ -2472,6 +2475,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return anim;
}
private void removeTaskInternal(int dismissedTaskId) {
UI_HELPER_EXECUTOR.getHandler().postDelayed(
() -> ActivityManagerWrapper.getInstance().removeTask(dismissedTaskId),
REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
}
/**
* @return {@code true} if one of the task thumbnails would intersect/overlap with the
* {@link #mSplitPlaceholderView}
@@ -3923,4 +3932,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
public RecentsAnimationController getRecentsAnimationController() {
return mRecentsAnimationController;
}
/** Update the current activity locus id to show the enabled state of Overview */
public void updateLocusId() {
String locusId = "Overview";
if (mOverviewStateEnabled && mActivity.isStarted()) {
locusId += "|ENABLED";
} else {
locusId += "|DISABLED";
}
final LocusId id = new LocusId(locusId);
// Set locus context is a binder call, don't want it to happen during a transition
UI_HELPER_EXECUTOR.post(() -> mActivity.setLocusContext(id, Bundle.EMPTY));
}
}
@@ -545,7 +545,13 @@ public class TaskView extends FrameLayout implements Reusable {
mIsClickableAsLiveTile = false;
RecentsView recentsView = getRecentsView();
RemoteAnimationTargets targets = recentsView.getLiveTileParams().getTargetSet();
final RemoteAnimationTargets targets = recentsView.getLiveTileParams().getTargetSet();
if (targets == null) {
// If the recents animation is cancelled somehow between the parent if block and
// here, try to launch the task as a non live tile task.
launcherNonLiveTileTask();
return;
}
AnimatorSet anim = new AnimatorSet();
TaskViewUtils.composeRecentsLaunchAnimator(
@@ -567,17 +573,21 @@ public class TaskView extends FrameLayout implements Reusable {
});
anim.start();
} else {
if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
// User tapped to select second split screen app
getRecentsView().confirmSplitSelect(this);
} else {
launchTaskAnimated();
}
launcherNonLiveTileTask();
}
mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_TAP);
}
private void launcherNonLiveTileTask() {
if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
// User tapped to select second split screen app
getRecentsView().confirmSplitSelect(this);
} else {
launchTaskAnimated();
}
}
/**
* Starts the task associated with this view and animates the startup.
* @return CompletionStage to indicate the animation completion or null if the launch failed.
@@ -107,7 +107,7 @@ public class FallbackRecentsTest {
mOrderSensitiveRules = RuleChain
.outerRule(new NavigationModeSwitchRule(mLauncher))
.around(new FailureWatcher(mDevice));
.around(new FailureWatcher(mDevice, mLauncher));
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="@android:color/system_neutral2_50"
android:lStar="30" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="20" />
</selector>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="15" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="10" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="@android:color/system_neutral1_50"
android:lStar="98" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="98" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="95" />
</selector>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="?attr/popupColorPrimary"
android:lStar="90" />
</selector>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:color="?attr/popupColorPrimary" />
</selector>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:color="?attr/popupColorPrimary" />
</selector>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:color="?attr/popupColorPrimary" />
</selector>
+6 -2
View File
@@ -18,14 +18,18 @@
<shape android:shape="rectangle">
<corners android:radius="@dimen/work_fab_radius" />
<solid android:color="?android:attr/colorControlHighlight" />
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
<padding
android:left="@dimen/work_profile_footer_padding"
android:right="@dimen/work_profile_footer_padding" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/work_fab_radius" />
<solid android:color="@color/all_apps_tab_background_selected" />
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
<padding
android:left="@dimen/work_profile_footer_padding"
android:right="@dimen/work_profile_footer_padding" />
</shape>
</item>
</selector>
+2
View File
@@ -33,6 +33,8 @@
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
android:fontFamily="sans-serif-medium"
android:textSize="20sp"
tools:text="No widgets available" />
<!-- Fast scroller popup -->
+1 -1
View File
@@ -42,7 +42,7 @@
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="@dimen/rounded_button_height"
android:id="@+id/action_btn"
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_profile_edu_accept"
+5 -5
View File
@@ -17,7 +17,7 @@
android:layout_height="wrap_content"
android:padding="@dimen/work_edu_card_margin"
android:orientation="vertical"
android:gravity="center">
android:gravity="center_horizontal">
<TextView
style="@style/PrimaryHeadline"
@@ -25,8 +25,7 @@
android:id="@+id/work_apps_paused_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="40dp"
android:text="@string/work_apps_paused_title"
android:textAlignment="center"
android:textSize="20sp" />
@@ -38,12 +37,13 @@
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_apps_paused_body"
android:textAlignment="center"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:textSize="16sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="@dimen/rounded_button_height"
android:id="@+id/enable_work_apps"
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_apps_enable_btn_text"
+2
View File
@@ -13,6 +13,7 @@
limitations under the License.
-->
<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TextHeadline"
android:id="@+id/work_mode_toggle"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
@@ -22,6 +23,7 @@
android:includeFontPadding="false"
android:drawableTint="@color/all_apps_tab_text"
android:textColor="@color/all_apps_tab_text"
android:textSize="14sp"
android:background="@drawable/work_apps_toggle_background"
android:drawablePadding="16dp"
android:drawableStart="@drawable/ic_corp_off"
-2
View File
@@ -26,8 +26,6 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowShowWallpaper">true</item>
<item name="folderTextColor">?attr/workspaceTextColor</item>
<item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:enforceStatusBarContrast">false</item>
<item name="android:enforceNavigationBarContrast">false</item>
-2
View File
@@ -26,8 +26,6 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowShowWallpaper">true</item>
<item name="folderTextColor">?attr/workspaceTextColor</item>
<item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
<item name="android:windowLayoutInDisplayCutoutMode">always</item>
<item name="android:enforceStatusBarContrast">false</item>
<item name="android:enforceNavigationBarContrast">false</item>
+1 -3
View File
@@ -39,9 +39,7 @@
<color name="text_color_tertiary_dark">@android:color/system_neutral2_400</color>
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
<color name="folder_background_light" android:lstar="98">@android:color/system_neutral1_50</color>
<color name="folder_background_dark" android:lstar="30">@android:color/system_neutral2_800</color>
<color name="folder_dot_color">@android:color/system_accent2_50</color>
+8 -8
View File
@@ -85,12 +85,12 @@
<!-- Spoken text for screen readers. This text lets a user know that the button is used to clear
the text that the user entered in the search box. [CHAR_LIMIT=none] -->
<string name="widgets_full_sheet_cancel_button_description">Clear text from search box</string>
<!-- Text shown when there is no widgets shown in the popup view showing all available widgets
installed on the device. [CHAR_LIMIT=none] -->
<string name="no_widgets_available">No widgets available</string>
<!-- Text shown when there are no matching widget search results for user's search query.
<!-- Text shown when there are no widgets or shortcuts that can be added to the device.
[CHAR_LIMIT=none] -->
<string name="no_search_results">No search results</string>
<string name="no_widgets_available">Widgets and shortcuts aren\'t available</string>
<!-- Text shown when there are no matching widget or shortcut search results for user's search
query. [CHAR_LIMIT=none] -->
<string name="no_search_results">No widgets or shortcuts found</string>
<!-- Tab label. A user can tap this tab to access their personal widgets. [CHAR_LIMIT=25] -->
<string name="widgets_full_sheet_personal_tab">Personal</string>
<!-- Tab label. A user can tap this tab to access their work widgets. [CHAR_LIMIT=25] -->
@@ -140,8 +140,8 @@
<string name="long_accessible_way_to_add_shortcut">Double-tap &amp; hold to move a shortcut or use custom actions.</string>
<skip />
<!-- Error message when user has filled a home screen -->
<string name="out_of_space">No more room on this Home screen.</string>
<!-- Error message when a user can't add more apps, widgets, or shortcuts to a Home screen. -->
<string name="out_of_space">No room on this Home screen</string>
<!-- Error message when user has filled the hotseat -->
<string name="hotseat_out_of_space">No more room in the Favorites tray</string>
@@ -394,7 +394,7 @@
<string name="work_profile_edu_accept">Got it</string>
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work apps are off</string>
<string name="work_apps_paused_title">Work apps are paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_body">Your work apps cant send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
-20
View File
@@ -26,8 +26,6 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowShowWallpaper">true</item>
<item name="folderTextColor">?attr/workspaceTextColor</item>
<item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
</style>
<style name="LauncherTheme" parent="@style/BaseLauncherTheme">
@@ -72,10 +70,6 @@
</style>
<style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
<item name="folderFillColor">@color/folder_background_dark</item>
<item name="folderTextColor">@color/workspace_text_color_light</item>
<item name="isFolderDarkText">false</item>
<item name="folderHintColor">@color/folder_hint_text_color_light</item>
<item name="disabledIconAlpha">.254</item>
</style>
@@ -87,12 +81,6 @@
<item name="workspaceKeyShadowColor">@android:color/transparent</item>
<item name="isWorkspaceDarkText">true</item>
<item name="workspaceStatusBarScrim">@null</item>
<item name="folderDotColor">@color/folder_dot_color</item>
<item name="folderFillColor">@color/folder_background_light</item>
<item name="folderIconBorderColor">#FF80868B</item>
<item name="folderTextColor">@color/workspace_text_color_dark</item>
<item name="isFolderDarkText">true</item>
<item name="folderHintColor">@color/folder_hint_text_color_dark</item>
</style>
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
@@ -125,25 +113,17 @@
</style>
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
<item name="folderFillColor">@color/folder_background_dark</item>
<item name="folderTextColor">@color/workspace_text_color_light</item>
<item name="isFolderDarkText">false</item>
<item name="folderHintColor">@color/folder_hint_text_color_light</item>
<item name="disabledIconAlpha">.54</item>
</style>
<style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
<item name="android:colorControlHighlight">#19212121</item>
<item name="folderFillColor">@color/folder_background_light</item>
<item name="workspaceTextColor">@color/workspace_text_color_dark</item>
<item name="workspaceShadowColor">@android:color/transparent</item>
<item name="workspaceAmbientShadowColor">@android:color/transparent</item>
<item name="workspaceKeyShadowColor">@android:color/transparent</item>
<item name="isWorkspaceDarkText">true</item>
<item name="workspaceStatusBarScrim">@null</item>
<item name="folderTextColor">@color/workspace_text_color_dark</item>
<item name="isFolderDarkText">true</item>
<item name="folderHintColor">@color/folder_hint_text_color_dark</item>
</style>
<!-- A derivative project can extend these themes to customize the application theme without
@@ -122,6 +122,8 @@ public final class LauncherAppWidgetProviderInfoTest {
@Test
public void initSpans_minResizeWidthSmallerThanCellWidth_shouldInitializeMinSpansToOne() {
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = 100;
info.minHeight = 100;
info.minResizeWidth = 20;
info.minResizeHeight = 20;
InvariantDeviceProfile idp = createIDP();
@@ -135,6 +137,8 @@ public final class LauncherAppWidgetProviderInfoTest {
@Test
public void initSpans_minResizeWidthLargerThanCellWidth_shouldInitializeMinSpans() {
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = 100;
info.minHeight = 100;
info.minResizeWidth = 80;
info.minResizeHeight = 80;
InvariantDeviceProfile idp = createIDP();
@@ -157,6 +161,8 @@ public final class LauncherAppWidgetProviderInfoTest {
Mockito.when(dp.shouldInsetWidgets()).thenReturn(true);
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = CELL_SIZE * 3;
info.minHeight = CELL_SIZE * 3;
info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
@@ -177,6 +183,8 @@ public final class LauncherAppWidgetProviderInfoTest {
dp.cellLayoutBorderSpacingPx = maxPadding - 1;
Mockito.when(dp.shouldInsetWidgets()).thenReturn(false);
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = CELL_SIZE * 3;
info.minHeight = CELL_SIZE * 3;
info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
@@ -186,6 +194,22 @@ public final class LauncherAppWidgetProviderInfoTest {
assertThat(info.minSpanY).isEqualTo(3);
}
@Test
public void
initSpans_minResizeWidthHeightLargerThanMinWidth_shouldUseMinWidthHeightAsMinSpans() {
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = 20;
info.minHeight = 20;
info.minResizeWidth = 80;
info.minResizeHeight = 80;
InvariantDeviceProfile idp = createIDP();
info.initSpans(mContext, idp);
assertThat(info.minSpanX).isEqualTo(1);
assertThat(info.minSpanY).isEqualTo(1);
}
@Test
public void isMinSizeFulfilled_minWidthAndHeightWithinGridSize_shouldReturnTrue() {
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
@@ -684,9 +684,6 @@ public class CellLayout extends ViewGroup {
if (child instanceof BubbleTextView) {
BubbleTextView bubbleChild = (BubbleTextView) child;
bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
if (mActivity.getDeviceProfile().isScalableGrid) {
bubbleChild.setCenterVertically(mContainerType != HOTSEAT);
}
}
child.setScaleX(mChildScale);
+18 -15
View File
@@ -152,10 +152,11 @@ public class DeviceProfile {
// Hotseat
public final int numShownHotseatIcons;
public int hotseatCellHeightPx;
private final int hotseatExtraVerticalSize;
// In portrait: size = height, in landscape: size = width
public int hotseatBarSizePx;
public final int hotseatBarTopPaddingPx;
public int hotseatBarBottomPaddingPx;
public final int hotseatBarBottomPaddingPx;
// Start is the side next to the nav bar, end is the side next to the workspace
public final int hotseatBarSidePaddingStartPx;
public final int hotseatBarSidePaddingEndPx;
@@ -331,13 +332,9 @@ public class DeviceProfile {
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
// Add a bit of space between nav bar and hotseat in vertical bar layout.
hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
int hotseatExtraVerticalSize =
hotseatExtraVerticalSize =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size);
hotseatBarSizePx = pxFromDp(inv.iconSize, mMetrics, 1f)
+ (isVerticalBarLayout()
? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
: (hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx
+ (isScalableGrid ? 0 : hotseatExtraVerticalSize)));
updateHotseatIconSize(pxFromDp(inv.iconSize, mMetrics, 1f));
overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
overviewTaskIconSizePx =
@@ -367,7 +364,6 @@ public class DeviceProfile {
extraHotseatBottomPadding = Math.round(paddingHotseatBottom * iconScale);
hotseatBarSizePx += extraHotseatBottomPadding;
hotseatBarBottomPaddingPx += extraHotseatBottomPadding;
} else if (!isVerticalBarLayout() && isPhone && isTallDevice) {
// We increase the hotseat size when there is extra space.
// ie. For a display with a large aspect ratio, we can keep the icons on the workspace
@@ -376,7 +372,6 @@ public class DeviceProfile {
int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- workspacePageIndicatorHeight;
hotseatBarSizePx += extraSpace;
hotseatBarBottomPaddingPx += extraSpace;
// Recalculate the available dimensions using the new hotseat size.
updateAvailableDimensions(res);
@@ -393,6 +388,17 @@ public class DeviceProfile {
new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE);
}
private void updateHotseatIconSize(int hotseatIconSizePx) {
hotseatCellHeightPx = hotseatIconSizePx;
if (isVerticalBarLayout()) {
hotseatBarSizePx = hotseatIconSizePx + hotseatBarSidePaddingStartPx
+ hotseatBarSidePaddingEndPx;
} else {
hotseatBarSizePx = hotseatIconSizePx + hotseatBarTopPaddingPx
+ hotseatBarBottomPaddingPx + (isScalableGrid ? 0 : hotseatExtraVerticalSize);
}
}
private void setCellLayoutBorderSpacing(int borderSpacing) {
cellLayoutBorderSpacingPx = isScalableGrid ? borderSpacing : 0;
}
@@ -578,11 +584,7 @@ public class DeviceProfile {
}
// Hotseat
if (isVerticalLayout) {
hotseatBarSizePx = iconSizePx + hotseatBarSidePaddingStartPx
+ hotseatBarSidePaddingEndPx;
}
hotseatCellHeightPx = iconSizePx;
updateHotseatIconSize(iconSizePx);
if (!isVerticalLayout) {
int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
@@ -795,7 +797,8 @@ public class DeviceProfile {
hotseatBarTopPaddingPx,
hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx
+ mInsets.right,
hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
hotseatBarSizePx - hotseatCellHeightPx - hotseatBarTopPaddingPx
+ cellLayoutBottomPaddingPx + mInsets.bottom);
}
return mHotseatPadding;
}
@@ -96,6 +96,9 @@ public class ExtendedEditText extends EditText {
}
}
// inherited class can override to change the appearance of the edit text.
public void show() {}
public void showKeyboard() {
mShowImeAfterFirstLayout = !showSoftInput();
}
+1 -1
View File
@@ -1080,7 +1080,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
if (ALL_APPS.equals(mPrevLauncherState) && !ALL_APPS.equals(state)
// Making sure mAllAppsSessionLogId is not null to avoid double logging.
&& mAllAppsSessionLogId != null) {
getAppsView().getSearchUiManager().resetSearch();
getAppsView().reset(false);
getStatsLogManager().logger()
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
@@ -138,12 +138,14 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
mBorderSpacing, null);
// Center the icon/folder
int cHeight = getCellContentHeight();
int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
int cellPaddingY = dp.isScalableGrid && mContainerType == WORKSPACE
? dp.cellYPaddingPx
: (int) Math.max(0, ((lp.height - cHeight) / 2f));
// No need to add padding when cell layout border spacing is present.
boolean noPadding = (dp.cellLayoutBorderSpacingPx > 0 && mContainerType == WORKSPACE)
boolean noPaddingX = (dp.cellLayoutBorderSpacingPx > 0 && mContainerType == WORKSPACE)
|| (dp.folderCellLayoutBorderSpacingPx > 0 && mContainerType == FOLDER);
int cellPaddingX = noPadding
int cellPaddingX = noPaddingX
? 0
: mContainerType == WORKSPACE
? dp.workspaceCellPaddingXPx
+1 -1
View File
@@ -2836,7 +2836,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
}
} else if (mDragInfo != null) {
// When drag is cancelled, reattach content view back to its original parent.
if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {
if (mDragInfo.cell instanceof LauncherAppWidgetHostView && d.dragView != null) {
d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
}
final CellLayout cellLayout = mLauncher.getCellLayout(
@@ -255,7 +255,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
mWorkModeSwitch.updateCurrentState(isEnabled);
}
mWorkAdapterProvider.updateCurrentState(isEnabled);
mAH[AdapterHolder.WORK].applyPadding();
}
private void hideInput() {
@@ -509,7 +508,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
R.layout.work_mode_fab, this, false);
this.addView(mWorkModeSwitch);
mWorkModeSwitch.setInsets(mInsets);
mWorkModeSwitch.post(this::resetWorkProfile);
mWorkModeSwitch.post(() -> {
mAH[AdapterHolder.WORK].applyPadding();
resetWorkProfile();
});
}
}
@@ -633,6 +635,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
mSearchModeWhileUsingTabs = true;
rebindAdapters(false); // hide tabs
}
mHeader.setCollapsed(true);
}
public void onClearSearchResult() {
@@ -715,8 +718,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
int bottom = mUsingTabs && mHeader.mHeaderCollapsed ? mHeader.getVisibleBottomBound()
: mSearchContainer.getBottom();
canvas.drawRect(0, 0, getWidth(), bottom + getTranslationY(),
canvas.drawRect(0, 0, canvas.getWidth(), bottom + getTranslationY(),
mHeaderPaint);
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && getTranslationY() == 0) {
mSearchUiManager.getEditText().setBackground(null);
}
}
}
@@ -783,7 +790,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
int bottomOffset = mWorkModeSwitch != null && mIsWork ? switchH : 0;
recyclerView.setPadding(padding.left, padding.top, padding.right,
padding.bottom + bottomOffset);
recyclerView.scrollToTop();
}
}
@@ -805,6 +811,9 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
getSearchView().setBackgroundColor(viewBG);
getFloatingHeaderView().setHeaderColor(viewBG);
invalidateHeader();
if (scrolledOffset == 0 && mSearchUiManager.getEditText() != null) {
mSearchUiManager.getEditText().show();
}
}
}
@@ -188,6 +188,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
StatsLogManager mgr = BaseDraggingActivity.fromContext(getContext()).getStatsLogManager();
switch (state) {
case SCROLL_STATE_DRAGGING:
requestFocus();
mgr.logger().sendToInteractionJankMonitor(
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
break;
@@ -78,6 +78,9 @@ public final class FeatureFlags {
public static final BooleanFlag UNSTABLE_SPRINGS = getDebugFlag(
"UNSTABLE_SPRINGS", false, "Enable unstable springs for quickstep animations");
public static final BooleanFlag ENABLE_LOCAL_COLOR_POPUPS = getDebugFlag(
"ENABLE_LOCAL_COLOR_POPUPS", false, "Enable local color extraction for popups.");
public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(
"KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper");
@@ -248,7 +251,7 @@ public final class FeatureFlags {
"Enables scrim over wallpaper for text protection.");
public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(
"WIDGETS_IN_LAUNCHER_PREVIEW", false,
"WIDGETS_IN_LAUNCHER_PREVIEW", true,
"Enables widgets in Launcher preview for the Wallpaper app.");
public static void initialize(Context context) {
@@ -245,9 +245,8 @@ public class FolderAnimationManager {
+ mDeviceProfile.folderCellHeightPx * 2;
int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
int left = mContent.getPaddingLeft() + page * lp.width;
Rect contentStart = new Rect(0, 0, width, height);
Rect contentEnd = new Rect(endRect.left + left, endRect.top, endRect.right + left,
endRect.bottom);
Rect contentStart = new Rect(left, 0, left + width, height);
Rect contentEnd = new Rect(left, 0, left + lp.width, lp.height);
play(a, getShape().createRevealAnimator(
mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
@@ -174,8 +174,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
folder.setFolderIcon(icon);
folder.bind(folderInfo);
icon.setFolder(folder);
icon.mBackground.paddingY = icon.isInHotseat()
? 0 : activityContext.getDeviceProfile().cellYPaddingPx;
return icon;
}
@@ -217,7 +215,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
icon.mBackground.paddingY = icon.isInHotseat() ? 0 : grid.cellYPaddingPx;
icon.mPreviewVerifier = new FolderGridOrganizer(activity.getDeviceProfile().inv);
icon.mPreviewVerifier.setFolderInfo(folderInfo);
icon.updatePreviewItems(false);
@@ -579,7 +576,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
public void setFolderBackground(PreviewBackground bg) {
mBackground = bg;
mBackground.setInvalidateDelegate(this);
mBackground.paddingY = isInHotseat() ? 0 : mActivity.getDeviceProfile().cellYPaddingPx;
}
@Override
@@ -627,7 +623,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
Rect iconBounds = mDotParams.iconBounds;
BubbleTextView.getIconBounds(this, iconBounds, mActivity.getDeviceProfile().iconSizePx);
iconBounds.offset(0, mBackground.paddingY);
float iconScale = (float) mBackground.previewSize / iconBounds.width();
Utilities.scaleRectAboutCenter(iconBounds, iconScale);
@@ -77,7 +77,6 @@ public class PreviewBackground extends CellLayout.DelegatedCellDrawing {
int previewSize;
int basePreviewOffsetX;
int basePreviewOffsetY;
int paddingY;
private CellLayout mDrawingDelegate;
@@ -161,7 +160,7 @@ public class PreviewBackground extends CellLayout.DelegatedCellDrawing {
previewSize = grid.folderIconSizePx;
basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
basePreviewOffsetY = paddingY + topPadding + grid.folderIconOffsetYPx;
basePreviewOffsetY = topPadding + grid.folderIconOffsetYPx;
// Stroke width is 1dp
mStrokeWidth = context.getResources().getDisplayMetrics().density;
@@ -26,6 +26,7 @@ import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially
import android.annotation.TargetApi;
import android.app.Fragment;
import android.app.WallpaperColors;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
@@ -42,6 +43,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -87,6 +89,7 @@ import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetHost;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LocalColorExtractor;
import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
@@ -206,8 +209,12 @@ public class LauncherPreviewRenderer extends ContextWrapper
private final Hotseat mHotseat;
private final CellLayout mWorkspace;
private final AppWidgetHost mAppWidgetHost;
private final SparseIntArray mWallpaperColorResources;
public LauncherPreviewRenderer(Context context,
InvariantDeviceProfile idp,
WallpaperColors wallpaperColors) {
public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp) {
super(context);
mUiHandler = new Handler(Looper.getMainLooper());
mContext = context;
@@ -260,9 +267,16 @@ public class LauncherPreviewRenderer extends ContextWrapper
mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
mDp.workspacePadding.bottom);
mAppWidgetHost = FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()
? new LauncherPreviewAppWidgetHost(context)
: null;
if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
mWallpaperColorResources = wallpaperColors != null
? LocalColorExtractor.newInstance(context)
.generateColorsOverride(wallpaperColors)
: null;
} else {
mAppWidgetHost = null;
mWallpaperColorResources = null;
}
}
/** Populate preview and render it. */
@@ -507,10 +521,12 @@ public class LauncherPreviewRenderer extends ContextWrapper
}
}
private static class LauncherPreviewAppWidgetHostView extends BaseLauncherAppWidgetHostView {
private class LauncherPreviewAppWidgetHostView extends BaseLauncherAppWidgetHostView {
private LauncherPreviewAppWidgetHostView(Context context) {
super(context);
if (Utilities.ATLEAST_S && mWallpaperColorResources != null) {
setColorResources(mWallpaperColorResources);
}
}
@Override
@@ -209,7 +209,7 @@ public class PreviewSurfaceRenderer {
if (mDestroyed) {
return;
}
View view = new LauncherPreviewRenderer(inflationContext, mIdp)
View view = new LauncherPreviewRenderer(inflationContext, mIdp, mWallpaperColors)
.getRenderedView(dataModel, widgetProviderInfoMap);
// This aspect scales the view to fit in the surface and centers it
final float scale = Math.min(mWidth / (float) view.getMeasuredWidth(),
@@ -27,6 +27,7 @@ import androidx.annotation.Nullable;
import androidx.slice.SliceItem;
import com.android.launcher3.R;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logger.LauncherAtom.FromState;
import com.android.launcher3.logger.LauncherAtom.ToState;
@@ -599,6 +600,13 @@ public class StatsLogManager implements ResourceBasedOverride {
return this;
}
/**
* Sets logging fields from provided {@link LauncherAtom.Slice}.
*/
default StatsLogger withSlice(LauncherAtom.Slice slice) {
return this;
}
/**
* Builds the final message and logs it as {@link EventEnum}.
*/
@@ -16,9 +16,12 @@
package com.android.launcher3.popup;
import static androidx.core.content.ContextCompat.getColorStateList;
import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_LOCAL_COLOR_POPUPS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,6 +31,7 @@ import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
@@ -133,6 +137,8 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
private final String mIterateChildrenTag;
private final int[] mColors;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mInflater = LayoutInflater.from(context);
@@ -171,9 +177,19 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
boolean isAboveAnotherSurface = getTopOpenViewWithType(mLauncher, TYPE_FOLDER) != null
|| mLauncher.getStateManager().getState() == LauncherState.ALL_APPS;
if (!isAboveAnotherSurface && Utilities.ATLEAST_S) {
if (!isAboveAnotherSurface && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) {
setupColorExtraction();
}
if (isAboveAnotherSurface) {
mColors = new int[] {
getColorStateList(context, R.color.popup_color_first).getDefaultColor()};
} else {
mColors = new int[] {
getColorStateList(context, R.color.popup_color_first).getDefaultColor(),
getColorStateList(context, R.color.popup_color_second).getDefaultColor(),
getColorStateList(context, R.color.popup_color_third).getDefaultColor()};
}
}
public ArrowPopup(Context context, AttributeSet attrs) {
@@ -220,6 +236,16 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
* Set the margins and radius of backgrounds after views are properly ordered.
*/
public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
assignMarginsAndBackgrounds(viewGroup, Color.TRANSPARENT);
}
/**
* @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}.
* Otherwise, we will use this color for all child views.
*/
private void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
final boolean getColorFromColorArray = backgroundColor == Color.TRANSPARENT;
int count = viewGroup.getChildCount();
int totalVisibleShortcuts = 0;
for (int i = 0; i < count; i++) {
@@ -229,8 +255,10 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
}
}
int numVisibleChild = 0;
int numVisibleShortcut = 0;
View lastView = null;
AnimatorSet colorAnimator = new AnimatorSet();
for (int i = 0; i < count; i++) {
View view = viewGroup.getChildAt(i);
if (view.getVisibility() == VISIBLE) {
@@ -242,8 +270,14 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams();
mlp.bottomMargin = 0;
if (getColorFromColorArray) {
backgroundColor = mColors[numVisibleChild % mColors.length];
}
if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
assignMarginsAndBackgrounds((ViewGroup) view);
assignMarginsAndBackgrounds((ViewGroup) view, backgroundColor);
numVisibleChild++;
continue;
}
@@ -261,8 +295,22 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
numVisibleShortcut++;
}
}
if (!ENABLE_LOCAL_COLOR_POPUPS.get()) {
setChildColor(view, backgroundColor, colorAnimator);
// Arrow color matches the first child or the last child.
if (!mIsAboveIcon && numVisibleChild == 0) {
mArrowColor = backgroundColor;
} else if (mIsAboveIcon) {
mArrowColor = backgroundColor;
}
}
numVisibleChild++;
}
}
colorAnimator.setDuration(0).start();
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
}
@@ -132,6 +132,12 @@ public class OptionsPopupView extends ArrowPopup
public static OptionsPopupView show(
Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow) {
return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
}
public static OptionsPopupView show(
Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow,
int width) {
OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
.inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
popup.mTargetRect = targetRect;
@@ -140,6 +146,9 @@ public class OptionsPopupView extends ArrowPopup
for (OptionItem item : items) {
DeepShortcutView view =
(DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup);
if (width > 0) {
view.getLayoutParams().width = width;
}
view.getIconView().setBackgroundDrawable(item.icon);
view.getBubbleText().setText(item.label);
view.setOnClickListener(popup);
@@ -105,9 +105,8 @@ public class SpringRelativeLayout extends RelativeLayout {
@NonNull @Override
protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
switch (direction) {
case DIRECTION_TOP:
return new EdgeEffectProxy(getContext(), mEdgeGlowTop);
if (direction == DIRECTION_TOP) {
return new EdgeEffectProxy(getContext(), mEdgeGlowTop);
}
return super.createEdgeEffect(view, direction);
}
@@ -160,8 +160,11 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
}
}
this.minSpanX = minSpanX;
this.minSpanY = minSpanY;
// If minSpanX/Y > spanX/Y, ignore the minSpanX/Y to match the behavior described in
// minResizeWidth & minResizeHeight Android documentation. See
// https://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo
this.minSpanX = Math.min(spanX, minSpanX);
this.minSpanY = Math.min(spanY, minSpanY);
this.maxSpanX = maxSpanX;
this.maxSpanY = maxSpanY;
this.mIsMinSizeFulfilled = Math.min(spanX, minSpanX) <= idp.numColumns
@@ -75,6 +75,14 @@ public class LocalColorExtractor implements ResourceBasedOverride {
*/
public void applyColorsOverride(Context base, WallpaperColors colors) { }
/**
* Generates color resource overrides from {@link WallpaperColors}.
*/
@Nullable
public SparseIntArray generateColorsOverride(WallpaperColors colors) {
return null;
}
/**
* Takes a view and returns its rect that can be used by the wallpaper local color extractor.
*
@@ -229,7 +229,7 @@ public abstract class AbstractLauncherUiTest {
protected TestRule getRulesInsideActivityMonitor() {
final RuleChain inner = RuleChain.outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mDevice));
.around(new FailureWatcher(mDevice, mLauncher));
return TestHelpers.isInLauncherProcess()
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher())
@@ -310,7 +310,6 @@ public abstract class AbstractLauncherUiTest {
assertEquals("Launcher crashed, pid mismatch:",
mLauncherPid, mLauncher.getPid().intValue());
}
checkDetectedLeaks(mLauncher);
} finally {
mLauncher.onTestFinish();
}
@@ -618,5 +617,6 @@ public abstract class AbstractLauncherUiTest {
isResumed);
}
protected void onLauncherActivityClose(Launcher launcher) { }
protected void onLauncherActivityClose(Launcher launcher) {
}
}
@@ -6,6 +6,9 @@ import android.util.Log;
import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -16,9 +19,11 @@ import java.io.IOException;
public class FailureWatcher extends TestWatcher {
private static final String TAG = "FailureWatcher";
final private UiDevice mDevice;
private final LauncherInstrumentation mLauncher;
public FailureWatcher(UiDevice device) {
public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) {
mDevice = device;
mLauncher = launcher;
}
private static void dumpViewHierarchy(UiDevice device) {
@@ -35,6 +40,12 @@ public class FailureWatcher extends TestWatcher {
}
}
@Override
protected void succeeded(Description description) {
super.succeeded(description);
AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
}
@Override
protected void failed(Throwable e, Description description) {
onError(mDevice, description, e);
@@ -75,4 +75,9 @@ public final class AppIcon extends Launchable {
protected void expectActivityStartEvents() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
}
@Override
protected String launchableType() {
return "app icon";
}
}
@@ -20,8 +20,6 @@ import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
import java.util.regex.Pattern;
/**
* Menu item in an app icon menu.
*/
@@ -51,4 +49,9 @@ public class AppIconMenuItem extends Launchable {
protected void expectActivityStartEvents() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
}
@Override
protected String launchableType() {
return "app icon menu item";
}
}
@@ -68,7 +68,7 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
}
protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
return false;
return mLauncher.isTablet();
}
protected void goToOverviewUnchecked() {
@@ -53,23 +53,29 @@ abstract class Launchable {
protected abstract void expectActivityStartEvents();
protected abstract String launchableType();
private Background launch(BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
final String label = mObject.getText();
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"clicking " + launchableType())) {
LauncherInstrumentation.log("Launchable.launch before click "
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
final String label = mObject.getText();
mLauncher.executeAndWaitForEvent(
() -> {
mLauncher.clickLauncherObject(mObject);
expectActivityStartEvents();
},
event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
() -> "Launching an app didn't open a new window: " + label);
mLauncher.executeAndWaitForEvent(
() -> {
mLauncher.clickLauncherObject(mObject);
expectActivityStartEvents();
},
event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
() -> "Launching an app didn't open a new window: " + label);
mLauncher.assertTrue(
"App didn't start: " + label + " (" + selector + ")",
TestHelpers.wait(Until.hasObject(selector), LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
mLauncher.assertTrue(
"App didn't start: " + label + " (" + selector + ")",
TestHelpers.wait(Until.hasObject(selector),
LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
}
}
/**
@@ -504,7 +504,7 @@ public final class LauncherInstrumentation {
void fail(String message) {
checkForAnomaly();
Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
"http://go/tapl test failure:\nSummary: " + getContextDescription()
"http://go/tapl test failure:\nContext: " + getContextDescription()
+ " - visible state is " + getVisibleStateMessage()
+ ";\nDetails: " + message, true)));
}
@@ -46,4 +46,9 @@ public final class Widget extends Launchable {
protected void addExpectedEventsForLongClick() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
}
@Override
protected String launchableType() {
return "widget";
}
}