Merging from ub-launcher3-rvc-qpr-dev @ build 6770831

Bug:150504032
Test: manual, presubmit on the source branch
x20/teams/android-launcher/merge/ub-launcher3-rvc-qpr-dev_rvc-qpr-dev_6770831.html

Change-Id: Ic07dd8bd495cd0e013a00a29d9d9f11e246dc568
Merged-In: I5e9c73a7ac3033fe82006c4bd72824f56b8988f8
This commit is contained in:
Tony Wickham
2020-08-18 04:59:10 +00:00
50 changed files with 1090 additions and 217 deletions
@@ -43,9 +43,11 @@ import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.MainThread;
import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.RemoteActionShortcut;
import com.android.launcher3.popup.SystemShortcut;
@@ -57,6 +59,7 @@ import com.android.launcher3.util.SimpleBroadcastReceiver;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
/**
* Data model for digital wellbeing status of apps.
@@ -72,6 +75,9 @@ public final class WellbeingModel {
private static final int MSG_FULL_REFRESH = 3;
// Welbeing contract
private static final String PATH_ACTIONS = "actions";
private static final String PATH_MINIMAL_DEVICE = "minimal_device";
private static final String METHOD_GET_MINIMAL_DEVICE_CONFIG = "get_minimal_device_config";
private static final String METHOD_GET_ACTIONS = "get_actions";
private static final String EXTRA_ACTIONS = "actions";
private static final String EXTRA_ACTION = "action";
@@ -104,15 +110,22 @@ public final class WellbeingModel {
mContentObserver = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
// Wellbeing reports that app actions have changed.
if (DEBUG || mIsInTest) {
Log.d(TAG, "ContentObserver.onChange() called with: selfChange = [" + selfChange
+ "], uri = [" + uri + "]");
Log.d(TAG, "ContentObserver.onChange() called with: selfChange = ["
+ selfChange + "], uri = [" + uri + "]");
}
Preconditions.assertUIThread();
updateWellbeingData();
if (uri.getPath().contains(PATH_ACTIONS)) {
// Wellbeing reports that app actions have changed.
updateWellbeingData();
} else if (uri.getPath().contains(PATH_MINIMAL_DEVICE)) {
// Wellbeing reports that minimal device state or config is changed.
updateLauncherModel();
}
}
};
FeatureFlags.ENABLE_MINIMAL_DEVICE.addChangeListener(mContext, this::updateLauncherModel);
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
context.registerReceiver(
@@ -146,14 +159,18 @@ public final class WellbeingModel {
private void restartObserver() {
final ContentResolver resolver = mContext.getContentResolver();
resolver.unregisterContentObserver(mContentObserver);
Uri actionsUri = apiBuilder().path("actions").build();
Uri actionsUri = apiBuilder().path(PATH_ACTIONS).build();
Uri minimalDeviceUri = apiBuilder().path(PATH_MINIMAL_DEVICE).build();
try {
resolver.registerContentObserver(
actionsUri, true /* notifyForDescendants */, mContentObserver);
resolver.registerContentObserver(
minimalDeviceUri, true /* notifyForDescendants */, mContentObserver);
} catch (Exception e) {
Log.e(TAG, "Failed to register content observer for " + actionsUri + ": " + e);
if (mIsInTest) throw new RuntimeException(e);
}
updateWellbeingData();
}
@@ -191,12 +208,42 @@ public final class WellbeingModel {
mWorkerHandler.sendEmptyMessage(MSG_FULL_REFRESH);
}
private void updateLauncherModel() {
if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) return;
// TODO: init Launcher in minimal device / normal mode
}
private Uri.Builder apiBuilder() {
return new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(mWellbeingProviderPkg + ".api");
}
/**
* Fetch most up-to-date minimal device config.
*/
@WorkerThread
private void runWithMinimalDeviceConfigs(Consumer<Bundle> consumer) {
if (DEBUG || mIsInTest) {
Log.d(TAG, "runWithMinimalDeviceConfigs() called");
}
Preconditions.assertNonUiThread();
final Uri contentUri = apiBuilder().build();
final Bundle remoteBundle;
try (ContentProviderClient client = mContext.getContentResolver()
.acquireUnstableContentProviderClient(contentUri)) {
remoteBundle = client.call(
METHOD_GET_MINIMAL_DEVICE_CONFIG, null /* args */, null /* extras */);
consumer.accept(remoteBundle);
} catch (Exception e) {
Log.e(TAG, "Failed to retrieve data from " + contentUri + ": " + e);
if (mIsInTest) throw new RuntimeException(e);
}
if (DEBUG || mIsInTest) Log.i(TAG, "runWithMinimalDeviceConfigs(): finished");
}
private boolean updateActions(String... packageNames) {
if (packageNames.length == 0) {
return true;
@@ -24,11 +24,13 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MO
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
@@ -63,6 +65,7 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher);
RECENTS_SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]);
ADJACENT_PAGE_OFFSET.set(mRecentsView, scaleAndOffset[1]);
TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
@@ -97,6 +100,8 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
@@ -92,7 +93,8 @@ public class AllAppsState extends LauncherState {
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {0.9f, 0};
float offset = ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher) ? 1 : 0;
return new float[] {0.9f, offset};
}
@Override
@@ -142,6 +142,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 1");
}
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping down to overview.
return NORMAL;
}
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
} else if (fromState == OVERVIEW) {
@@ -28,6 +28,7 @@ import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_REC
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
import android.annotation.TargetApi;
@@ -52,6 +53,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.views.RecentsView;
@@ -106,7 +108,7 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract void onAssistantVisibilityChanged(float visibility);
public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorPlaybackController> callback);
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
public abstract ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener);
@@ -319,11 +321,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
protected final ACTIVITY_TYPE mActivity;
private final STATE_TYPE mStartState;
private final Consumer<AnimatorPlaybackController> mCallback;
private final Consumer<AnimatorControllerWithResistance> mCallback;
private boolean mIsAttachedToWindow;
DefaultAnimationFactory(Consumer<AnimatorPlaybackController> callback) {
DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
mCallback = callback;
mActivity = getCreatedActivity();
@@ -351,7 +353,14 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
controller.setEndAction(() -> mActivity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? mOverviewState : mBackgroundState,
false));
mCallback.accept(controller);
RecentsView recentsView = mActivity.getOverviewPanel();
AnimatorControllerWithResistance controllerWithResistance =
AnimatorControllerWithResistance.createForRecents(controller, mActivity,
recentsView.getPagedViewOrientedState(), mActivity.getDeviceProfile(),
recentsView, RECENTS_SCALE_PROPERTY, recentsView,
TASK_SECONDARY_TRANSLATION);
mCallback.accept(controllerWithResistance);
// Creating the activity controller animation sometimes reapplies the launcher state
// (because we set the animation as the current state animation), so we reapply the
@@ -184,8 +184,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
@Override
public void updateFinalShift() {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
mTaskViewSimulator.apply(mTransformParams);
}
@@ -0,0 +1,230 @@
/*
* 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.quickstep.util;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.FloatProperty;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.RecentsView;
/**
* Controls an animation that can go beyond progress = 1, at which point resistance should be
* applied. Internally, this is a wrapper around 2 {@link AnimatorPlaybackController}s, one that
* runs from progress 0 to 1 like normal, then one that seamlessly continues that animation but
* starts applying resistance as well.
*/
public class AnimatorControllerWithResistance {
/**
* How much farther we can drag past overview in 2-button mode, as a factor of the distance
* it takes to drag from an app to overview.
*/
public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f;
private enum RecentsParams {
FROM_APP(0.75f, 0.5f, 1f),
FROM_OVERVIEW(1f, 0.75f, 0.5f);
RecentsParams(float scaleStartResist, float scaleMaxResist, float translationFactor) {
this.scaleStartResist = scaleStartResist;
this.scaleMaxResist = scaleMaxResist;
this.translationFactor = translationFactor;
}
/**
* Start slowing down the rate of scaling down when recents view is smaller than this scale.
*/
public final float scaleStartResist;
/**
* Recents view will reach this scale at the very end of the drag.
*/
public final float scaleMaxResist;
/**
* How much translation to apply to RecentsView when the drag reaches the top of the screen,
* where 0 will keep it centered and 1 will have it barely touch the top of the screen.
*/
public final float translationFactor;
}
private static final TimeInterpolator RECENTS_SCALE_RESIST_INTERPOLATOR = DEACCEL;
private static final TimeInterpolator RECENTS_TRANSLATE_RESIST_INTERPOLATOR = LINEAR;
private final AnimatorPlaybackController mNormalController;
private final AnimatorPlaybackController mResistanceController;
// Initialize to -1 so the first 0 gets applied.
private float mLastNormalProgress = -1;
private float mLastResistProgress;
public AnimatorControllerWithResistance(AnimatorPlaybackController normalController,
AnimatorPlaybackController resistanceController) {
mNormalController = normalController;
mResistanceController = resistanceController;
}
public AnimatorPlaybackController getNormalController() {
return mNormalController;
}
/**
* Applies the current progress of the animation.
* @param progress From 0 to maxProgress, where 1 is the target we are animating towards.
* @param maxProgress > 1, this is where the resistance will be applied.
*/
public void setProgress(float progress, float maxProgress) {
float normalProgress = Utilities.boundToRange(progress, 0, 1);
if (normalProgress != mLastNormalProgress) {
mLastNormalProgress = normalProgress;
mNormalController.setPlayFraction(normalProgress);
}
if (maxProgress <= 1) {
return;
}
float resistProgress = progress <= 1 ? 0 : Utilities.getProgress(progress, 1, maxProgress);
if (resistProgress != mLastResistProgress) {
mLastResistProgress = resistProgress;
mResistanceController.setPlayFraction(resistProgress);
}
}
/**
* Applies resistance to recents when swiping up past its target position.
* @param normalController The controller to run from 0 to 1 before this resistance applies.
* @param context Used to compute start and end values.
* @param recentsOrientedState Used to compute start and end values.
* @param dp Used to compute start and end values.
* @param scaleTarget The target for the scaleProperty.
* @param scaleProperty Animate the value to change the scale of the window/recents view.
* @param translationTarget The target for the translationProperty.
* @param translationProperty Animate the value to change the translation of the recents view.
*/
public static <SCALE, TRANSLATION> AnimatorControllerWithResistance createForRecents(
AnimatorPlaybackController normalController, Context context,
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
FloatProperty<SCALE> scaleProperty, TRANSLATION translationTarget,
FloatProperty<TRANSLATION> translationProperty) {
PendingAnimation resistAnim = createRecentsResistanceAnim(null, context,
recentsOrientedState, dp, scaleTarget, scaleProperty, translationTarget,
translationProperty, RecentsParams.FROM_APP);
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
return new AnimatorControllerWithResistance(normalController, resistanceController);
}
/**
* Creates the resistance animation for {@link #createForRecents}, or can be used separately
* when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}.
*/
public static <SCALE, TRANSLATION> PendingAnimation createRecentsResistanceAnim(
@Nullable PendingAnimation resistAnim, Context context,
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
FloatProperty<SCALE> scaleProperty, TRANSLATION translationTarget,
FloatProperty<TRANSLATION> translationProperty, RecentsParams params) {
Rect startRect = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect,
recentsOrientedState.getOrientationHandler());
long distanceToCover = startRect.bottom;
boolean isTwoButtonMode = SysUINavigationMode.getMode(context) == TWO_BUTTONS;
if (isTwoButtonMode) {
// We can only drag a small distance past overview, not to the top of the screen.
distanceToCover = (long)
((dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR);
}
if (resistAnim == null) {
resistAnim = new PendingAnimation(distanceToCover * 2);
}
PointF pivot = new PointF();
float fullscreenScale = recentsOrientedState.getFullScreenScaleAndPivot(
startRect, dp, pivot);
float startScale = 1;
float prevScaleRate = (fullscreenScale - startScale) / (dp.heightPx - startRect.bottom);
// This is what the scale would be at the end of the drag if we didn't apply resistance.
float endScale = startScale - prevScaleRate * distanceToCover;
final TimeInterpolator scaleInterpolator;
if (isTwoButtonMode) {
// We are bounded by the distance of the drag, so we don't need to apply resistance.
scaleInterpolator = LINEAR;
} else {
// Create an interpolator that resists the scale so the scale doesn't get smaller than
// RECENTS_SCALE_MAX_RESIST.
float startResist = Utilities.getProgress(params.scaleStartResist , startScale,
endScale);
float maxResist = Utilities.getProgress(params.scaleMaxResist, startScale, endScale);
scaleInterpolator = t -> {
if (t < startResist) {
return t;
}
float resistProgress = Utilities.getProgress(t, startResist, 1);
resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
return startResist + resistProgress * (maxResist - startResist);
};
}
resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale,
scaleInterpolator);
if (!isTwoButtonMode) {
// Compute where the task view would be based on the end scale, if we didn't translate.
RectF endRectF = new RectF(startRect);
Matrix temp = new Matrix();
temp.setScale(params.scaleMaxResist, params.scaleMaxResist, pivot.x, pivot.y);
temp.mapRect(endRectF);
// Translate such that the task view touches the top of the screen when drag does.
float endTranslation = endRectF.top * recentsOrientedState.getOrientationHandler()
.getSecondaryTranslationDirectionFactor() * params.translationFactor;
resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation,
RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
}
return resistAnim;
}
/**
* Helper method to update or create a PendingAnimation suitable for animating
* a RecentsView interaction that started from the overview state.
*/
public static PendingAnimation createRecentsResistanceFromOverviewAnim(
BaseDraggingActivity activity, @Nullable PendingAnimation resistanceAnim) {
RecentsView recentsView = activity.getOverviewPanel();
return createRecentsResistanceAnim(resistanceAnim, activity,
recentsView.getPagedViewOrientedState(), activity.getDeviceProfile(),
recentsView, RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION,
RecentsParams.FROM_OVERVIEW);
}
}