Merging from ub-launcher3-rvc-dev @ build 6557059 am: fa6e021ce6 am: 0b5bf8218d
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/11727216 Change-Id: Id88e52d8dd32331c30b5abcc26a584d923df5f2e
This commit is contained in:
+6
-2
@@ -52,6 +52,7 @@ public class HotseatEduController {
|
|||||||
|
|
||||||
private final Launcher mLauncher;
|
private final Launcher mLauncher;
|
||||||
private final Hotseat mHotseat;
|
private final Hotseat mHotseat;
|
||||||
|
private final HotseatRestoreHelper mRestoreHelper;
|
||||||
private List<WorkspaceItemInfo> mPredictedApps;
|
private List<WorkspaceItemInfo> mPredictedApps;
|
||||||
private HotseatEduDialog mActiveDialog;
|
private HotseatEduDialog mActiveDialog;
|
||||||
|
|
||||||
@@ -59,9 +60,10 @@ public class HotseatEduController {
|
|||||||
private IntArray mNewScreens = null;
|
private IntArray mNewScreens = null;
|
||||||
private Runnable mOnOnboardingComplete;
|
private Runnable mOnOnboardingComplete;
|
||||||
|
|
||||||
HotseatEduController(Launcher launcher, Runnable runnable) {
|
HotseatEduController(Launcher launcher, HotseatRestoreHelper restoreHelper, Runnable runnable) {
|
||||||
mLauncher = launcher;
|
mLauncher = launcher;
|
||||||
mHotseat = launcher.getHotseat();
|
mHotseat = launcher.getHotseat();
|
||||||
|
mRestoreHelper = restoreHelper;
|
||||||
mOnOnboardingComplete = runnable;
|
mOnOnboardingComplete = runnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,11 +71,14 @@ public class HotseatEduController {
|
|||||||
* Checks what type of migration should be used and migrates hotseat
|
* Checks what type of migration should be used and migrates hotseat
|
||||||
*/
|
*/
|
||||||
void migrate() {
|
void migrate() {
|
||||||
|
mRestoreHelper.createBackup();
|
||||||
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
|
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
|
||||||
migrateToFolder();
|
migrateToFolder();
|
||||||
} else {
|
} else {
|
||||||
migrateHotseatWhole();
|
migrateHotseatWhole();
|
||||||
}
|
}
|
||||||
|
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, R.string.hotseat_turn_off,
|
||||||
|
null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +89,6 @@ public class HotseatEduController {
|
|||||||
*/
|
*/
|
||||||
private int migrateToFolder() {
|
private int migrateToFolder() {
|
||||||
ArrayDeque<FolderInfo> folders = new ArrayDeque<>();
|
ArrayDeque<FolderInfo> folders = new ArrayDeque<>();
|
||||||
|
|
||||||
ArrayList<WorkspaceItemInfo> putIntoFolder = new ArrayList<>();
|
ArrayList<WorkspaceItemInfo> putIntoFolder = new ArrayList<>();
|
||||||
|
|
||||||
//separate folders and items that can get in folders
|
//separate folders and items that can get in folders
|
||||||
|
|||||||
+2
-1
@@ -16,7 +16,8 @@
|
|||||||
package com.android.launcher3.hybridhotseat;
|
package com.android.launcher3.hybridhotseat;
|
||||||
|
|
||||||
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
|
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
|
||||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
|
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType
|
||||||
|
.HYBRID_HOTSEAT_CANCELED;
|
||||||
|
|
||||||
import android.animation.PropertyValuesHolder;
|
import android.animation.PropertyValuesHolder;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|||||||
+8
-2
@@ -92,6 +92,8 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
private Launcher mLauncher;
|
private Launcher mLauncher;
|
||||||
private final Hotseat mHotseat;
|
private final Hotseat mHotseat;
|
||||||
|
|
||||||
|
private final HotseatRestoreHelper mRestoreHelper;
|
||||||
|
|
||||||
private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
|
private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
|
||||||
|
|
||||||
private DynamicItemCache mDynamicItemCache;
|
private DynamicItemCache mDynamicItemCache;
|
||||||
@@ -129,6 +131,7 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
|
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
|
||||||
launcher.getDeviceProfile().inv.addOnChangeListener(this);
|
launcher.getDeviceProfile().inv.addOnChangeListener(this);
|
||||||
mHotseat.addOnAttachStateChangeListener(this);
|
mHotseat.addOnAttachStateChangeListener(this);
|
||||||
|
mRestoreHelper = new HotseatRestoreHelper(mLauncher);
|
||||||
if (mHotseat.isAttachedToWindow()) {
|
if (mHotseat.isAttachedToWindow()) {
|
||||||
onViewAttachedToWindow(mHotseat);
|
onViewAttachedToWindow(mHotseat);
|
||||||
}
|
}
|
||||||
@@ -297,7 +300,8 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
});
|
});
|
||||||
setPauseUIUpdate(false);
|
setPauseUIUpdate(false);
|
||||||
if (!isEduSeen()) {
|
if (!isEduSeen()) {
|
||||||
mHotseatEduController = new HotseatEduController(mLauncher, this::createPredictor);
|
mHotseatEduController = new HotseatEduController(mLauncher, mRestoreHelper,
|
||||||
|
this::createPredictor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,9 +324,11 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
updateDependencies();
|
updateDependencies();
|
||||||
bindItems(items, false, null);
|
bindItems(items, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPredictedApps(List<AppTarget> appTargets) {
|
private void setPredictedApps(List<AppTarget> appTargets) {
|
||||||
mComponentKeyMappers.clear();
|
mComponentKeyMappers.clear();
|
||||||
|
if (appTargets.isEmpty() && mRestoreHelper.shouldRestoreToBackup()) {
|
||||||
|
mRestoreHelper.restoreBackup();
|
||||||
|
}
|
||||||
StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
|
StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
|
||||||
ArrayList<ComponentKey> componentKeys = new ArrayList<>();
|
ArrayList<ComponentKey> componentKeys = new ArrayList<>();
|
||||||
for (AppTarget appTarget : appTargets) {
|
for (AppTarget appTarget : appTargets) {
|
||||||
|
|||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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.hybridhotseat;
|
||||||
|
|
||||||
|
import static com.android.launcher3.LauncherSettings.Favorites.HYBRID_HOTSEAT_BACKUP_TABLE;
|
||||||
|
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
|
||||||
|
|
||||||
|
import com.android.launcher3.InvariantDeviceProfile;
|
||||||
|
import com.android.launcher3.Launcher;
|
||||||
|
import com.android.launcher3.LauncherSettings;
|
||||||
|
import com.android.launcher3.model.GridBackupTable;
|
||||||
|
import com.android.launcher3.provider.LauncherDbUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class to manage migration revert restoration for hybrid hotseat
|
||||||
|
*/
|
||||||
|
public class HotseatRestoreHelper {
|
||||||
|
private final Launcher mLauncher;
|
||||||
|
private boolean mBackupExists;
|
||||||
|
|
||||||
|
HotseatRestoreHelper(Launcher context) {
|
||||||
|
mLauncher = context;
|
||||||
|
setupBackupTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a snapshot backup of Favorite table for future restoration use.
|
||||||
|
*/
|
||||||
|
public synchronized void createBackup() {
|
||||||
|
try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
|
||||||
|
LauncherSettings.Settings.call(
|
||||||
|
mLauncher.getContentResolver(),
|
||||||
|
LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
|
||||||
|
.getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||||
|
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
|
||||||
|
GridBackupTable backupTable = new GridBackupTable(mLauncher,
|
||||||
|
transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
|
||||||
|
idp.numRows);
|
||||||
|
backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||||
|
transaction.commit();
|
||||||
|
LauncherSettings.Settings.call(mLauncher.getContentResolver(),
|
||||||
|
LauncherSettings.Settings.METHOD_REFRESH_HOTSEAT_RESTORE_TABLE);
|
||||||
|
mBackupExists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and restores a previously saved snapshow of Favorites table
|
||||||
|
*/
|
||||||
|
public void restoreBackup() {
|
||||||
|
try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
|
||||||
|
LauncherSettings.Settings.call(
|
||||||
|
mLauncher.getContentResolver(),
|
||||||
|
LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
|
||||||
|
.getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||||
|
if (!tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE)) {
|
||||||
|
mBackupExists = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
|
||||||
|
GridBackupTable backupTable = new GridBackupTable(mLauncher,
|
||||||
|
transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
|
||||||
|
idp.numRows);
|
||||||
|
backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true);
|
||||||
|
transaction.commit();
|
||||||
|
mBackupExists = false;
|
||||||
|
mLauncher.getModel().forceReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if prediction controller should attempt restoring a backup
|
||||||
|
*/
|
||||||
|
public synchronized boolean shouldRestoreToBackup() {
|
||||||
|
return mBackupExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setupBackupTable() {
|
||||||
|
try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
|
||||||
|
LauncherSettings.Settings.call(
|
||||||
|
mLauncher.getContentResolver(),
|
||||||
|
LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
|
||||||
|
.getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||||
|
mBackupExists = tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -37,6 +37,7 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
|
|||||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
|
||||||
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
|
||||||
@@ -210,6 +211,7 @@ public class QuickstepAtomicAnimationFactory extends
|
|||||||
}
|
}
|
||||||
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
|
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
|
||||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
|
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
|
||||||
|
config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
|
||||||
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
|
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
|
||||||
&& removeShelfFromOverview(mActivity)
|
&& removeShelfFromOverview(mActivity)
|
||||||
? OVERSHOOT_1_2
|
? OVERSHOOT_1_2
|
||||||
|
|||||||
+2
-3
@@ -33,11 +33,11 @@ import com.android.launcher3.anim.PendingAnimation;
|
|||||||
import com.android.launcher3.statehandlers.DepthController;
|
import com.android.launcher3.statehandlers.DepthController;
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||||
|
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||||
import com.android.quickstep.util.TaskViewSimulator;
|
import com.android.quickstep.util.TaskViewSimulator;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider for the atomic (for 3-button mode) remote window animation from the app to the overview.
|
* Provider for the atomic (for 3-button mode) remote window animation from the app to the overview.
|
||||||
@@ -132,8 +132,7 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
|||||||
|
|
||||||
TransformParams params = new TransformParams()
|
TransformParams params = new TransformParams()
|
||||||
.setTargetSet(targets)
|
.setTargetSet(targets)
|
||||||
.setSyncTransactionApplier(
|
.setSyncTransactionApplier(new SurfaceTransactionApplier(mActivity.getRootView()));
|
||||||
new SyncRtSurfaceTransactionApplierCompat(mActivity.getRootView()));
|
|
||||||
|
|
||||||
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
|
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
|
||||||
params.setBaseBuilderProxy((builder, app, p)
|
params.setBaseBuilderProxy((builder, app, p)
|
||||||
|
|||||||
@@ -40,13 +40,14 @@ import com.android.launcher3.util.WindowBounds;
|
|||||||
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
|
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
|
||||||
import com.android.quickstep.util.ActiveGestureLog;
|
import com.android.quickstep.util.ActiveGestureLog;
|
||||||
import com.android.quickstep.util.ActivityInitListener;
|
import com.android.quickstep.util.ActivityInitListener;
|
||||||
|
import com.android.quickstep.util.RectFSpringAnim;
|
||||||
|
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.quickstep.views.TaskView;
|
import com.android.quickstep.views.TaskView;
|
||||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||||
import com.android.systemui.shared.system.InputConsumerController;
|
import com.android.systemui.shared.system.InputConsumerController;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -114,10 +115,10 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
public abstract Intent getLaunchIntent();
|
public abstract Intent getLaunchIntent();
|
||||||
|
|
||||||
protected void linkRecentsViewScroll() {
|
protected void linkRecentsViewScroll() {
|
||||||
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
|
SurfaceTransactionApplier.create(mRecentsView, applier -> {
|
||||||
mTransformParams.setSyncTransactionApplier(applier);
|
mTransformParams.setSyncTransactionApplier(applier);
|
||||||
runOnRecentsAnimationStart(() ->
|
runOnRecentsAnimationStart(() ->
|
||||||
mRecentsAnimationTargets.addDependentTransactionApplier(applier));
|
mRecentsAnimationTargets.addReleaseCheck(applier));
|
||||||
});
|
});
|
||||||
|
|
||||||
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
|
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
|
||||||
@@ -356,7 +357,8 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
if (mWindowTransitionController != null) {
|
if (mWindowTransitionController != null) {
|
||||||
float progress = mCurrentShift.value / mDragLengthFactor;
|
float progress = mCurrentShift.value / mDragLengthFactor;
|
||||||
mWindowTransitionController.setPlayFraction(progress);
|
mWindowTransitionController.setPlayFraction(progress);
|
||||||
|
}
|
||||||
|
if (mRecentsAnimationTargets != null) {
|
||||||
if (mRecentsViewScrollLinked) {
|
if (mRecentsViewScrollLinked) {
|
||||||
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
|
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
|
||||||
}
|
}
|
||||||
@@ -364,6 +366,17 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||||
|
HomeAnimationFactory homeAnimationFactory) {
|
||||||
|
RectFSpringAnim anim =
|
||||||
|
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
|
||||||
|
if (mRecentsAnimationTargets != null) {
|
||||||
|
mRecentsAnimationTargets.addReleaseCheck(anim);
|
||||||
|
}
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
|
|
||||||
BaseSwipeUpHandler newHandler(
|
BaseSwipeUpHandler newHandler(
|
||||||
|
|||||||
+8
-6
@@ -310,8 +310,8 @@ public final class LauncherActivityInterface extends
|
|||||||
@Override
|
@Override
|
||||||
protected float getExtraSpace(Context context, DeviceProfile dp,
|
protected float getExtraSpace(Context context, DeviceProfile dp,
|
||||||
PagedOrientationHandler orientationHandler) {
|
PagedOrientationHandler orientationHandler) {
|
||||||
if (dp.isVerticalBarLayout() ||
|
if ((dp.isVerticalBarLayout() && !showOverviewActions(context))
|
||||||
hideShelfInTwoButtonLandscape(context, orientationHandler)) {
|
|| hideShelfInTwoButtonLandscape(context, orientationHandler)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
@@ -319,12 +319,14 @@ public final class LauncherActivityInterface extends
|
|||||||
//TODO: this needs to account for the swipe gesture height and accessibility
|
//TODO: this needs to account for the swipe gesture height and accessibility
|
||||||
// UI when shown.
|
// UI when shown.
|
||||||
float actionsBottomMargin = 0;
|
float actionsBottomMargin = 0;
|
||||||
if (getMode(context) == Mode.THREE_BUTTONS) {
|
if (!dp.isVerticalBarLayout()) {
|
||||||
actionsBottomMargin = res.getDimensionPixelSize(
|
if (getMode(context) == Mode.THREE_BUTTONS) {
|
||||||
|
actionsBottomMargin = res.getDimensionPixelSize(
|
||||||
R.dimen.overview_actions_bottom_margin_three_button);
|
R.dimen.overview_actions_bottom_margin_three_button);
|
||||||
} else {
|
} else {
|
||||||
actionsBottomMargin = res.getDimensionPixelSize(
|
actionsBottomMargin = res.getDimensionPixelSize(
|
||||||
R.dimen.overview_actions_bottom_margin_gesture);
|
R.dimen.overview_actions_bottom_margin_gesture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
float actionsHeight = actionsBottomMargin
|
float actionsHeight = actionsBottomMargin
|
||||||
+ res.getDimensionPixelSize(R.dimen.overview_actions_height);
|
+ res.getDimensionPixelSize(R.dimen.overview_actions_height);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package com.android.quickstep;
|
|||||||
|
|
||||||
import static android.view.Display.DEFAULT_DISPLAY;
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
|
||||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -35,6 +37,7 @@ import android.view.View;
|
|||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
||||||
import com.android.launcher3.model.WellbeingModel;
|
import com.android.launcher3.model.WellbeingModel;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
@@ -83,10 +86,12 @@ public interface TaskShortcutFactory {
|
|||||||
|
|
||||||
private final int mIconRes;
|
private final int mIconRes;
|
||||||
private final int mTextRes;
|
private final int mTextRes;
|
||||||
|
private final LauncherEvent mLauncherEvent;
|
||||||
|
|
||||||
MultiWindowFactory(int iconRes, int textRes) {
|
MultiWindowFactory(int iconRes, int textRes, LauncherEvent launcherEvent) {
|
||||||
mIconRes = iconRes;
|
mIconRes = iconRes;
|
||||||
mTextRes = textRes;
|
mTextRes = textRes;
|
||||||
|
mLauncherEvent = launcherEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId);
|
protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId);
|
||||||
@@ -102,7 +107,8 @@ public interface TaskShortcutFactory {
|
|||||||
if (!isAvailable(activity, task.key.displayId)) {
|
if (!isAvailable(activity, task.key.displayId)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this);
|
return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this,
|
||||||
|
mLauncherEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,11 +120,12 @@ public interface TaskShortcutFactory {
|
|||||||
private final TaskThumbnailView mThumbnailView;
|
private final TaskThumbnailView mThumbnailView;
|
||||||
private final TaskView mTaskView;
|
private final TaskView mTaskView;
|
||||||
private final MultiWindowFactory mFactory;
|
private final MultiWindowFactory mFactory;
|
||||||
|
private final LauncherEvent mLauncherEvent;
|
||||||
|
|
||||||
public MultiWindowSystemShortcut(int iconRes, int textRes,
|
public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
|
||||||
BaseDraggingActivity activity, TaskView taskView, MultiWindowFactory factory) {
|
TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
|
||||||
super(iconRes, textRes, activity, dummyInfo(taskView));
|
super(iconRes, textRes, activity, dummyInfo(taskView));
|
||||||
|
mLauncherEvent = launcherEvent;
|
||||||
mHandler = new Handler(Looper.getMainLooper());
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
mTaskView = taskView;
|
mTaskView = taskView;
|
||||||
mRecentsView = activity.getOverviewPanel();
|
mRecentsView = activity.getOverviewPanel();
|
||||||
@@ -203,12 +210,13 @@ public interface TaskShortcutFactory {
|
|||||||
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
||||||
future, animStartedListener, mHandler, true /* scaleUp */,
|
future, animStartedListener, mHandler, true /* scaleUp */,
|
||||||
taskKey.displayId);
|
taskKey.displayId);
|
||||||
|
mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.buildProto());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(
|
TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(R.drawable.ic_split_screen,
|
||||||
R.drawable.ic_split_screen, R.string.recent_task_option_split_screen) {
|
R.string.recent_task_option_split_screen, LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
|
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
|
||||||
@@ -241,8 +249,8 @@ public interface TaskShortcutFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TaskShortcutFactory FREE_FORM = new MultiWindowFactory(
|
TaskShortcutFactory FREE_FORM = new MultiWindowFactory(R.drawable.ic_split_screen,
|
||||||
R.drawable.ic_split_screen, R.string.recent_task_option_freeform) {
|
R.string.recent_task_option_freeform, LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
|
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import com.android.launcher3.anim.PendingAnimation;
|
|||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.statehandlers.DepthController;
|
import com.android.launcher3.statehandlers.DepthController;
|
||||||
import com.android.launcher3.util.DefaultDisplay;
|
import com.android.launcher3.util.DefaultDisplay;
|
||||||
|
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||||
import com.android.quickstep.util.TaskViewSimulator;
|
import com.android.quickstep.util.TaskViewSimulator;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
@@ -49,7 +50,6 @@ import com.android.quickstep.views.TaskThumbnailView;
|
|||||||
import com.android.quickstep.views.TaskView;
|
import com.android.quickstep.views.TaskView;
|
||||||
import com.android.systemui.shared.recents.model.Task;
|
import com.android.systemui.shared.recents.model.Task;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
|
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
|
||||||
@@ -128,11 +128,10 @@ public final class TaskViewUtils {
|
|||||||
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
|
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
|
||||||
PendingAnimation out) {
|
PendingAnimation out) {
|
||||||
|
|
||||||
SyncRtSurfaceTransactionApplierCompat applier =
|
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
|
||||||
new SyncRtSurfaceTransactionApplierCompat(v);
|
|
||||||
final RemoteAnimationTargets targets =
|
final RemoteAnimationTargets targets =
|
||||||
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
|
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
|
||||||
targets.addDependentTransactionApplier(applier);
|
targets.addReleaseCheck(applier);
|
||||||
|
|
||||||
TransformParams params = new TransformParams()
|
TransformParams params = new TransformParams()
|
||||||
.setSyncTransactionApplier(applier)
|
.setSyncTransactionApplier(applier)
|
||||||
|
|||||||
+33
-15
@@ -30,6 +30,7 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYS
|
|||||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
|
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.RemoteAction;
|
import android.app.RemoteAction;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
@@ -134,10 +135,10 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
|
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System Action ID to show all apps. This ID should follow the ones in
|
* System Action ID to show all apps.
|
||||||
* com.android.systemui.accessibility.SystemActions.
|
* TODO: Use AccessibilityService's corresponding global action constant in S
|
||||||
*/
|
*/
|
||||||
private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
|
private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
|
||||||
|
|
||||||
private int mBackGestureNotificationCounter = -1;
|
private int mBackGestureNotificationCounter = -1;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -467,10 +468,17 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
|
|
||||||
final int action = event.getAction();
|
final int action = event.getAction();
|
||||||
if (action == ACTION_DOWN) {
|
if (action == ACTION_DOWN) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
|
||||||
|
}
|
||||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||||
GestureState newGestureState;
|
GestureState newGestureState;
|
||||||
|
|
||||||
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
|
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME,
|
||||||
|
"TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
|
||||||
|
}
|
||||||
// Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
|
// Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
|
||||||
// onConsumerInactive and wipe the previous gesture state
|
// onConsumerInactive and wipe the previous gesture state
|
||||||
GestureState prevGestureState = new GestureState(mGestureState);
|
GestureState prevGestureState = new GestureState(mGestureState);
|
||||||
@@ -480,18 +488,22 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
|
|
||||||
ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
|
ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
|
||||||
mUncheckedConsumer = mConsumer;
|
mUncheckedConsumer = mConsumer;
|
||||||
} else if (mDeviceState.isUserUnlocked()
|
} else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
|
||||||
&& mDeviceState.isFullyGesturalNavMode()
|
|
||||||
&& mDeviceState.canTriggerAssistantAction(event)) {
|
|
||||||
newGestureState = createGestureState();
|
newGestureState = createGestureState();
|
||||||
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
|
ActivityManager.RunningTaskInfo runningTask = newGestureState.getRunningTask();
|
||||||
// not interrupt it. QuickSwitch assumes that interruption can only happen if the
|
if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
|
||||||
// next gesture is also quick switch.
|
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
|
||||||
mUncheckedConsumer = new AssistantInputConsumer(
|
// should not interrupt it. QuickSwitch assumes that interruption can only
|
||||||
this,
|
// happen if the next gesture is also quick switch.
|
||||||
newGestureState,
|
mUncheckedConsumer = new AssistantInputConsumer(
|
||||||
InputConsumer.NO_OP, mInputMonitorCompat,
|
this,
|
||||||
mOverviewComponentObserver.assistantGestureIsConstrained());
|
newGestureState,
|
||||||
|
InputConsumer.NO_OP, mInputMonitorCompat,
|
||||||
|
mOverviewComponentObserver.assistantGestureIsConstrained());
|
||||||
|
} else {
|
||||||
|
newGestureState = DEFAULT_STATE;
|
||||||
|
mUncheckedConsumer = InputConsumer.NO_OP;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
newGestureState = DEFAULT_STATE;
|
newGestureState = DEFAULT_STATE;
|
||||||
mUncheckedConsumer = InputConsumer.NO_OP;
|
mUncheckedConsumer = InputConsumer.NO_OP;
|
||||||
@@ -537,6 +549,9 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
|
|
||||||
private InputConsumer newConsumer(GestureState previousGestureState,
|
private InputConsumer newConsumer(GestureState previousGestureState,
|
||||||
GestureState newGestureState, MotionEvent event) {
|
GestureState newGestureState, MotionEvent event) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
|
||||||
|
}
|
||||||
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
|
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
|
||||||
|
|
||||||
if (!mDeviceState.isUserUnlocked()) {
|
if (!mDeviceState.isUserUnlocked()) {
|
||||||
@@ -548,6 +563,9 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
return mResetGestureInputConsumer;
|
return mResetGestureInputConsumer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
|
||||||
|
}
|
||||||
|
|
||||||
// When there is an existing recents animation running, bypass systemState check as this is
|
// When there is an existing recents animation running, bypass systemState check as this is
|
||||||
// a followup gesture and the first gesture started in a valid system state.
|
// a followup gesture and the first gesture started in a valid system state.
|
||||||
@@ -559,7 +577,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
handleOrientationSetup(base);
|
handleOrientationSetup(base);
|
||||||
}
|
}
|
||||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||||
if (mDeviceState.canTriggerAssistantAction(event)) {
|
if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
|
||||||
base = new AssistantInputConsumer(
|
base = new AssistantInputConsumer(
|
||||||
this,
|
this,
|
||||||
newGestureState,
|
newGestureState,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.android.launcher3.R;
|
|||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.FlingSpringAnim;
|
import com.android.launcher3.anim.FlingSpringAnim;
|
||||||
import com.android.launcher3.util.DynamicResource;
|
import com.android.launcher3.util.DynamicResource;
|
||||||
|
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
|
||||||
import com.android.systemui.plugins.ResourceProvider;
|
import com.android.systemui.plugins.ResourceProvider;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -39,7 +40,7 @@ import java.util.List;
|
|||||||
* Applies spring forces to animate from a starting rect to a target rect,
|
* Applies spring forces to animate from a starting rect to a target rect,
|
||||||
* while providing update callbacks to the caller.
|
* while providing update callbacks to the caller.
|
||||||
*/
|
*/
|
||||||
public class RectFSpringAnim {
|
public class RectFSpringAnim extends ReleaseCheck {
|
||||||
|
|
||||||
private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
|
private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
|
||||||
new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
|
new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
|
||||||
@@ -116,6 +117,7 @@ public class RectFSpringAnim {
|
|||||||
ResourceProvider rp = DynamicResource.provider(context);
|
ResourceProvider rp = DynamicResource.provider(context);
|
||||||
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
|
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
|
||||||
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
|
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
|
||||||
|
setCanRelease(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTargetPositionChanged() {
|
public void onTargetPositionChanged() {
|
||||||
@@ -190,10 +192,12 @@ public class RectFSpringAnim {
|
|||||||
maybeOnEnd();
|
maybeOnEnd();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setCanRelease(false);
|
||||||
|
mAnimsStarted = true;
|
||||||
|
|
||||||
mRectXAnim.start();
|
mRectXAnim.start();
|
||||||
mRectYAnim.start();
|
mRectYAnim.start();
|
||||||
mRectScaleAnim.start();
|
mRectScaleAnim.start();
|
||||||
mAnimsStarted = true;
|
|
||||||
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
||||||
animatorListener.onAnimationStart(null);
|
animatorListener.onAnimationStart(null);
|
||||||
}
|
}
|
||||||
@@ -245,6 +249,7 @@ public class RectFSpringAnim {
|
|||||||
private void maybeOnEnd() {
|
private void maybeOnEnd() {
|
||||||
if (mAnimsStarted && isEnded()) {
|
if (mAnimsStarted && isEnded()) {
|
||||||
mAnimsStarted = false;
|
mAnimsStarted = false;
|
||||||
|
setCanRelease(true);
|
||||||
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
||||||
animatorListener.onAnimationEnd(null);
|
animatorListener.onAnimationEnd(null);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -121,8 +121,11 @@ public class StaggeredWorkspaceAnim {
|
|||||||
addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
|
addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
View qsb = launcher.findViewById(R.id.search_container_all_apps);
|
if (launcher.getAppsView().getSearchUiManager()
|
||||||
addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
|
.isQsbVisible(NORMAL.getVisibleElements(launcher))) {
|
||||||
|
addStaggeredAnimationForView(launcher.getAppsView().getSearchView(),
|
||||||
|
grid.inv.numRows + 2, totalRows);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animateOverviewScrim) {
|
if (animateOverviewScrim) {
|
||||||
|
|||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.shared.system.TransactionCompat.deferTransactionUntil;
|
||||||
|
import static com.android.systemui.shared.system.TransactionCompat.setEarlyWakeup;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.SurfaceControl.Transaction;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
|
||||||
|
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||||
|
import com.android.systemui.shared.system.ViewRootImplCompat;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to apply surface transactions in sync with RenderThread similar to
|
||||||
|
* android.view.SyncRtSurfaceTransactionApplier
|
||||||
|
* with some Launcher specific utility methods
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.R)
|
||||||
|
public class SurfaceTransactionApplier extends ReleaseCheck {
|
||||||
|
|
||||||
|
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
|
||||||
|
|
||||||
|
private final SurfaceControl mBarrierSurfaceControl;
|
||||||
|
private final ViewRootImplCompat mTargetViewRootImpl;
|
||||||
|
private final Handler mApplyHandler;
|
||||||
|
|
||||||
|
private int mLastSequenceNumber = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetView The view in the surface that acts as synchronization anchor.
|
||||||
|
*/
|
||||||
|
public SurfaceTransactionApplier(View targetView) {
|
||||||
|
mTargetViewRootImpl = new ViewRootImplCompat(targetView);
|
||||||
|
mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl();
|
||||||
|
mApplyHandler = new Handler(this::onApplyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean onApplyMessage(Message msg) {
|
||||||
|
if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
|
||||||
|
setCanRelease(msg.arg1 == mLastSequenceNumber);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules applying surface parameters on the next frame.
|
||||||
|
*
|
||||||
|
* @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
|
||||||
|
* this method to avoid synchronization issues.
|
||||||
|
*/
|
||||||
|
public void scheduleApply(final SurfaceParams... params) {
|
||||||
|
View view = mTargetViewRootImpl.getView();
|
||||||
|
if (view == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastSequenceNumber++;
|
||||||
|
final int toApplySeqNo = mLastSequenceNumber;
|
||||||
|
setCanRelease(false);
|
||||||
|
mTargetViewRootImpl.registerRtFrameCallback(frame -> {
|
||||||
|
if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
|
||||||
|
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
|
||||||
|
.sendToTarget();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Transaction t = new Transaction();
|
||||||
|
for (int i = params.length - 1; i >= 0; i--) {
|
||||||
|
SurfaceParams surfaceParams = params[i];
|
||||||
|
if (surfaceParams.surface.isValid()) {
|
||||||
|
deferTransactionUntil(t, surfaceParams.surface, mBarrierSurfaceControl, frame);
|
||||||
|
surfaceParams.applyTo(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setEarlyWakeup(t);
|
||||||
|
t.apply();
|
||||||
|
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
|
||||||
|
.sendToTarget();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make sure a frame gets scheduled.
|
||||||
|
view.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
|
||||||
|
* attached if necessary.
|
||||||
|
*/
|
||||||
|
public static void create(
|
||||||
|
final View targetView, final Consumer<SurfaceTransactionApplier> callback) {
|
||||||
|
if (targetView == null) {
|
||||||
|
// No target view, no applier
|
||||||
|
callback.accept(null);
|
||||||
|
} else if (new ViewRootImplCompat(targetView).isValid()) {
|
||||||
|
// Already attached, we're good to go
|
||||||
|
callback.accept(new SurfaceTransactionApplier(targetView));
|
||||||
|
} else {
|
||||||
|
// Haven't been attached before we can get the view root
|
||||||
|
targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onViewAttachedToWindow(View v) {
|
||||||
|
targetView.removeOnAttachStateChangeListener(this);
|
||||||
|
callback.accept(new SurfaceTransactionApplier(targetView));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewDetachedFromWindow(View v) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ public class TransformParams {
|
|||||||
private float mTargetAlpha;
|
private float mTargetAlpha;
|
||||||
private float mCornerRadius;
|
private float mCornerRadius;
|
||||||
private RemoteAnimationTargets mTargetSet;
|
private RemoteAnimationTargets mTargetSet;
|
||||||
private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
|
private SurfaceTransactionApplier mSyncTransactionApplier;
|
||||||
|
|
||||||
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||||
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||||
@@ -112,7 +112,7 @@ public class TransformParams {
|
|||||||
* are computed based on these TransformParams.
|
* are computed based on these TransformParams.
|
||||||
*/
|
*/
|
||||||
public TransformParams setSyncTransactionApplier(
|
public TransformParams setSyncTransactionApplier(
|
||||||
SyncRtSurfaceTransactionApplierCompat applier) {
|
SurfaceTransactionApplier applier) {
|
||||||
mSyncTransactionApplier = applier;
|
mSyncTransactionApplier = applier;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-4
@@ -21,6 +21,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
|
|||||||
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
|
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -33,6 +34,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.util.MultiValueAlpha;
|
import com.android.launcher3.util.MultiValueAlpha;
|
||||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||||
|
import com.android.quickstep.SysUINavigationMode;
|
||||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||||
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
|
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
|
||||||
|
|
||||||
@@ -129,6 +131,12 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
|||||||
updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
|
updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
|
||||||
|
}
|
||||||
|
|
||||||
public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
|
public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
mHiddenFlags |= visibilityFlags;
|
mHiddenFlags |= visibilityFlags;
|
||||||
@@ -152,10 +160,13 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
|||||||
return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
|
return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Updates vertical margins for different navigation mode. */
|
/** Updates vertical margins for different navigation mode or configuration changes. */
|
||||||
public void updateVerticalMarginForNavModeChange(Mode mode) {
|
public void updateVerticalMargin(Mode mode) {
|
||||||
int bottomMargin = 0;
|
int bottomMargin;
|
||||||
if (mode == Mode.THREE_BUTTONS) {
|
int orientation = getResources().getConfiguration().orientation;
|
||||||
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
|
bottomMargin = 0;
|
||||||
|
} else if (mode == Mode.THREE_BUTTONS) {
|
||||||
bottomMargin = getResources()
|
bottomMargin = getResources()
|
||||||
.getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
|
.getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ import com.android.quickstep.ViewUtils;
|
|||||||
import com.android.quickstep.util.LayoutUtils;
|
import com.android.quickstep.util.LayoutUtils;
|
||||||
import com.android.quickstep.util.RecentsOrientedState;
|
import com.android.quickstep.util.RecentsOrientedState;
|
||||||
import com.android.quickstep.util.SplitScreenBounds;
|
import com.android.quickstep.util.SplitScreenBounds;
|
||||||
|
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.systemui.plugins.ResourceProvider;
|
import com.android.systemui.plugins.ResourceProvider;
|
||||||
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
||||||
@@ -135,7 +136,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
|
|||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.LauncherEventUtil;
|
import com.android.systemui.shared.system.LauncherEventUtil;
|
||||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -211,7 +211,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
protected final BaseActivityInterface mSizeStrategy;
|
protected final BaseActivityInterface mSizeStrategy;
|
||||||
protected RecentsAnimationController mRecentsAnimationController;
|
protected RecentsAnimationController mRecentsAnimationController;
|
||||||
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
||||||
protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
|
protected SurfaceTransactionApplier mSyncTransactionApplier;
|
||||||
protected int mTaskWidth;
|
protected int mTaskWidth;
|
||||||
protected int mTaskHeight;
|
protected int mTaskHeight;
|
||||||
protected boolean mEnableDrawingLiveTile = false;
|
protected boolean mEnableDrawingLiveTile = false;
|
||||||
@@ -492,6 +492,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
|
|
||||||
public void init(OverviewActionsView actionsView) {
|
public void init(OverviewActionsView actionsView) {
|
||||||
mActionsView = actionsView;
|
mActionsView = actionsView;
|
||||||
|
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -501,7 +502,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
|
mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
|
||||||
mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
|
mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
|
||||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
|
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
|
||||||
mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
|
mSyncTransactionApplier = new SurfaceTransactionApplier(this);
|
||||||
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
||||||
mIdp.addOnChangeListener(this);
|
mIdp.addOnChangeListener(this);
|
||||||
mIPinnedStackAnimationListener.setActivity(mActivity);
|
mIPinnedStackAnimationListener.setActivity(mActivity);
|
||||||
@@ -1626,8 +1627,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
: View.LAYOUT_DIRECTION_RTL);
|
: View.LAYOUT_DIRECTION_RTL);
|
||||||
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
|
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
|
||||||
mActivity.getDragLayer().recreateControllers();
|
mActivity.getDragLayer().recreateControllers();
|
||||||
|
boolean isInLandscape = touchRotation != 0
|
||||||
|
|| mOrientationState.getLauncherRotation() != ROTATION_0;
|
||||||
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
|
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
|
||||||
touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
|
!mOrientationState.canLauncherRotate() && isInLandscape);
|
||||||
resetPaddingFromTaskSize();
|
resetPaddingFromTaskSize();
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
|||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
@@ -222,8 +223,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
setOutlineProvider(mOutlineProvider);
|
setOutlineProvider(mOutlineProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Builds proto for logging */
|
/** Builds proto for logging */
|
||||||
protected LauncherAtom.ItemInfo buildProto() {
|
public LauncherAtom.ItemInfo buildProto() {
|
||||||
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
|
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
|
||||||
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||||
itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
|
itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
|
||||||
@@ -424,6 +425,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
private boolean showTaskMenu(int action) {
|
private boolean showTaskMenu(int action) {
|
||||||
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
|
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
|
||||||
mMenuView = TaskMenuView.showForTask(this);
|
mMenuView = TaskMenuView.showForTask(this);
|
||||||
|
mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
|
||||||
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
|
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
|
||||||
LauncherLogProto.ItemType.TASK_ICON);
|
LauncherLogProto.ItemType.TASK_ICON);
|
||||||
if (mMenuView != null) {
|
if (mMenuView != null) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/gesture_tutorial_background_color">
|
android:background="?android:attr/colorBackground">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/gesture_tutorial_ripple_view"
|
android:id="@+id/gesture_tutorial_ripple_view"
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
|
android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
|
||||||
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
|
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
android:src="@drawable/gesture_tutorial_close_button"/>
|
android:src="@drawable/gesture_tutorial_close_button"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -14,5 +14,6 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
|
<color name="back_arrow_color_light">#FFFFFFFF</color>
|
||||||
<color name="back_arrow_color_dark">#99000000</color>
|
<color name="back_arrow_color_dark">#99000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -83,6 +83,8 @@
|
|||||||
<string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
|
<string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
|
||||||
<!-- tip shown if user declines migration and has some open spots for prediction -->
|
<!-- tip shown if user declines migration and has some open spots for prediction -->
|
||||||
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
|
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
|
||||||
|
<!-- tip shown when user migrates and predictions are enabled in hotseat -->
|
||||||
|
<string name="hotsaet_tip_prediction_enabled">App suggestions Enabled</string>
|
||||||
|
|
||||||
<!-- content description for hotseat items -->
|
<!-- content description for hotseat items -->
|
||||||
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
|
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
|
||||||
@@ -110,7 +112,6 @@
|
|||||||
<!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
|
<!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
|
||||||
<string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
|
<string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Title shown during interactive part of Home gesture tutorial. [CHAR LIMIT=30] -->
|
<!-- Title shown during interactive part of Home gesture tutorial. [CHAR LIMIT=30] -->
|
||||||
<string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
|
<string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
|
||||||
<!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
|
<!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
|
||||||
@@ -122,6 +123,17 @@
|
|||||||
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
|
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
|
||||||
<string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
|
<string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
|
||||||
|
|
||||||
|
<!-- Title shown during interactive part of Overview gesture tutorial. [CHAR LIMIT=30] -->
|
||||||
|
<string name="overview_gesture_tutorial_playground_title" translatable="false">Tutorial: Switch Apps</string>
|
||||||
|
<!-- Subtitle shown during interactive parts of Overview gesture tutorial. [CHAR LIMIT=60] -->
|
||||||
|
<string name="overview_gesture_tutorial_playground_subtitle" translatable="false">Swipe up from the bottom of the screen and hold</string>
|
||||||
|
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
|
||||||
|
<string name="overview_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
|
||||||
|
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the Home gesture is detected. [CHAR LIMIT=100] -->
|
||||||
|
<string name="overview_gesture_feedback_home_detected" translatable="false">Try holding the window for longer before releasing</string>
|
||||||
|
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
|
||||||
|
<string name="overview_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up and pause</string>
|
||||||
|
|
||||||
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
|
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
|
||||||
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
|
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
|
||||||
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
|
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
|
||||||
|
|||||||
@@ -35,14 +35,14 @@
|
|||||||
<style name="TextAppearance.GestureTutorial.Title"
|
<style name="TextAppearance.GestureTutorial.Title"
|
||||||
parent="TextAppearance.GestureTutorial">
|
parent="TextAppearance.GestureTutorial">
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:textColor">@color/gesture_tutorial_title_color</item>
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
<item name="android:textSize">28sp</item>
|
<item name="android:textSize">28sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.GestureTutorial.Subtitle"
|
<style name="TextAppearance.GestureTutorial.Subtitle"
|
||||||
parent="TextAppearance.GestureTutorial">
|
parent="TextAppearance.GestureTutorial">
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:textColor">@color/gesture_tutorial_subtitle_color</item>
|
<item name="android:textColor">?android:attr/textColorTertiary</item>
|
||||||
<item name="android:letterSpacing">0.03</item>
|
<item name="android:letterSpacing">0.03</item>
|
||||||
<item name="android:textSize">21sp</item>
|
<item name="android:textSize">21sp</item>
|
||||||
</style>
|
</style>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<style name="TextAppearance.GestureTutorial.Feedback"
|
<style name="TextAppearance.GestureTutorial.Feedback"
|
||||||
parent="TextAppearance.GestureTutorial">
|
parent="TextAppearance.GestureTutorial">
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:textColor">@color/gesture_tutorial_feedback_color</item>
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
<item name="android:letterSpacing">0.03</item>
|
<item name="android:letterSpacing">0.03</item>
|
||||||
<item name="android:textSize">21sp</item>
|
<item name="android:textSize">21sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
public void onNavigationModeChanged(Mode newMode) {
|
public void onNavigationModeChanged(Mode newMode) {
|
||||||
getDragLayer().recreateControllers();
|
getDragLayer().recreateControllers();
|
||||||
if (mActionsView != null && isOverviewActionsEnabled()) {
|
if (mActionsView != null && isOverviewActionsEnabled()) {
|
||||||
mActionsView.updateVerticalMarginForNavModeChange(newMode);
|
mActionsView.updateVerticalMargin(newMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
||||||
getOverviewPanel().bringToFront();
|
getOverviewPanel().bringToFront();
|
||||||
mActionsView.bringToFront();
|
mActionsView.bringToFront();
|
||||||
mActionsView.updateVerticalMarginForNavModeChange(SysUINavigationMode.getMode(this));
|
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ import com.android.quickstep.RemoteAnimationTargets;
|
|||||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||||
|
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||||
import com.android.systemui.shared.system.ActivityCompat;
|
import com.android.systemui.shared.system.ActivityCompat;
|
||||||
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
||||||
import com.android.systemui.shared.system.QuickStepContract;
|
import com.android.systemui.shared.system.QuickStepContract;
|
||||||
@@ -89,7 +90,6 @@ import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
|
|||||||
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
|
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
|
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||||
|
|
||||||
@@ -455,9 +455,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||||||
|
|
||||||
RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
|
RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
|
||||||
wallpaperTargets, MODE_OPENING);
|
wallpaperTargets, MODE_OPENING);
|
||||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
SurfaceTransactionApplier surfaceApplier =
|
||||||
new SyncRtSurfaceTransactionApplierCompat(floatingView);
|
new SurfaceTransactionApplier(floatingView);
|
||||||
openingTargets.addDependentTransactionApplier(surfaceApplier);
|
openingTargets.addReleaseCheck(surfaceApplier);
|
||||||
|
|
||||||
// Scale the app icon to take up the entire screen. This simplifies the math when
|
// Scale the app icon to take up the entire screen. This simplifies the math when
|
||||||
// animating the app window position / scale.
|
// animating the app window position / scale.
|
||||||
@@ -714,8 +714,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||||||
*/
|
*/
|
||||||
private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets,
|
private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets,
|
||||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
|
||||||
new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
|
|
||||||
ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
|
ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
|
||||||
unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
|
unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
|
||||||
float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
|
float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
|
||||||
@@ -743,8 +742,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||||||
*/
|
*/
|
||||||
private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
|
private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
|
||||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
|
||||||
new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
|
|
||||||
Matrix matrix = new Matrix();
|
Matrix matrix = new Matrix();
|
||||||
Point tmpPos = new Point();
|
Point tmpPos = new Point();
|
||||||
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
|
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public final class WellbeingModel {
|
|||||||
private static final String EXTRA_ACTION = "action";
|
private static final String EXTRA_ACTION = "action";
|
||||||
private static final String EXTRA_MAX_NUM_ACTIONS_SHOWN = "max_num_actions_shown";
|
private static final String EXTRA_MAX_NUM_ACTIONS_SHOWN = "max_num_actions_shown";
|
||||||
private static final String EXTRA_PACKAGES = "packages";
|
private static final String EXTRA_PACKAGES = "packages";
|
||||||
|
private static final String EXTRA_SUCCESS = "success";
|
||||||
|
|
||||||
public static final MainThreadInitializedObject<WellbeingModel> INSTANCE =
|
public static final MainThreadInitializedObject<WellbeingModel> INSTANCE =
|
||||||
new MainThreadInitializedObject<>(WellbeingModel::new);
|
new MainThreadInitializedObject<>(WellbeingModel::new);
|
||||||
@@ -221,6 +222,7 @@ public final class WellbeingModel {
|
|||||||
params.putInt(EXTRA_MAX_NUM_ACTIONS_SHOWN, 1);
|
params.putInt(EXTRA_MAX_NUM_ACTIONS_SHOWN, 1);
|
||||||
// Perform wellbeing call .
|
// Perform wellbeing call .
|
||||||
remoteActionBundle = client.call(METHOD_GET_ACTIONS, null, params);
|
remoteActionBundle = client.call(METHOD_GET_ACTIONS, null, params);
|
||||||
|
if (!remoteActionBundle.getBoolean(EXTRA_SUCCESS, true)) return false;
|
||||||
|
|
||||||
synchronized (mModelLock) {
|
synchronized (mModelLock) {
|
||||||
// Remove the entries for requested packages, and then update the fist with what we
|
// Remove the entries for requested packages, and then update the fist with what we
|
||||||
@@ -281,9 +283,9 @@ public final class WellbeingModel {
|
|||||||
// Remove all existing messages
|
// Remove all existing messages
|
||||||
mWorkerHandler.removeCallbacksAndMessages(null);
|
mWorkerHandler.removeCallbacksAndMessages(null);
|
||||||
final String[] packageNames = mContext.getSystemService(LauncherApps.class)
|
final String[] packageNames = mContext.getSystemService(LauncherApps.class)
|
||||||
.getActivityList(null, Process.myUserHandle()).stream()
|
.getActivityList(null, Process.myUserHandle()).stream()
|
||||||
.map(li -> li.getApplicationInfo().packageName).distinct()
|
.map(li -> li.getApplicationInfo().packageName).distinct()
|
||||||
.toArray(String[]::new);
|
.toArray(String[]::new);
|
||||||
if (!updateActions(packageNames)) {
|
if (!updateActions(packageNames)) {
|
||||||
scheduleRefreshRetry(msg);
|
scheduleRefreshRetry(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.launcher3.statehandlers;
|
package com.android.launcher3.statehandlers;
|
||||||
|
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
|
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
|
||||||
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -191,11 +192,12 @@ public class DepthController implements StateHandler<LauncherState> {
|
|||||||
|
|
||||||
float toDepth = toState.getDepth(mLauncher);
|
float toDepth = toState.getDepth(mLauncher);
|
||||||
if (Float.compare(mDepth, toDepth) != 0) {
|
if (Float.compare(mDepth, toDepth) != 0) {
|
||||||
animation.setFloat(this, DEPTH, toDepth, LINEAR);
|
animation.setFloat(this, DEPTH, toDepth, config.getInterpolator(ANIM_DEPTH, LINEAR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDepth(float depth) {
|
private void setDepth(float depth) {
|
||||||
|
depth = Utilities.boundToRange(depth, 0, 1);
|
||||||
// Round out the depth to dedupe frequent, non-perceptable updates
|
// Round out the depth to dedupe frequent, non-perceptable updates
|
||||||
int depthI = (int) (depth * 256);
|
int depthI = (int) (depth * 256);
|
||||||
float depthF = depthI / 256f;
|
float depthF = depthI / 256f;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.view.Surface;
|
|||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.ResourceUtils;
|
import com.android.launcher3.ResourceUtils;
|
||||||
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.util.DefaultDisplay;
|
import com.android.launcher3.util.DefaultDisplay;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -246,6 +247,10 @@ class OrientationTouchTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean touchInValidSwipeRegions(float x, float y) {
|
boolean touchInValidSwipeRegions(float x, float y) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "touchInValidSwipeRegions " + x + "," + y + " in "
|
||||||
|
+ mLastRectTouched);
|
||||||
|
}
|
||||||
if (mLastRectTouched != null) {
|
if (mLastRectTouched != null) {
|
||||||
return mLastRectTouched.contains(x, y);
|
return mLastRectTouched.contains(x, y);
|
||||||
}
|
}
|
||||||
@@ -287,10 +292,16 @@ class OrientationTouchTransformer {
|
|||||||
|
|
||||||
for (int i = 0; i < MAX_ORIENTATIONS; i++) {
|
for (int i = 0; i < MAX_ORIENTATIONS; i++) {
|
||||||
OrientationRectF rect = mSwipeTouchRegions.get(i);
|
OrientationRectF rect = mSwipeTouchRegions.get(i);
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "transform:DOWN, rect=" + rect);
|
||||||
|
}
|
||||||
if (rect == null) {
|
if (rect == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rect.applyTransform(event, false)) {
|
if (rect.applyTransform(event, false)) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setting mLastRectTouched");
|
||||||
|
}
|
||||||
mLastRectTouched = rect;
|
mLastRectTouched = rect;
|
||||||
mLastRectRotation = rect.mRotation;
|
mLastRectRotation = rect.mRotation;
|
||||||
if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) {
|
if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) {
|
||||||
|
|||||||
@@ -525,13 +525,15 @@ public class RecentsAnimationDeviceState implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ev An ACTION_DOWN motion event
|
* @param ev An ACTION_DOWN motion event
|
||||||
* @return whether the given motion event can trigger the assistant.
|
* @param task Info for the currently running task
|
||||||
|
* @return whether the given motion event can trigger the assistant over the current task.
|
||||||
*/
|
*/
|
||||||
public boolean canTriggerAssistantAction(MotionEvent ev) {
|
public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
|
||||||
return mAssistantAvailable
|
return mAssistantAvailable
|
||||||
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
||||||
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
|
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
|
||||||
&& !isLockToAppActive();
|
&& !isLockToAppActive()
|
||||||
|
&& !isGestureBlockedActivity(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,19 +16,16 @@
|
|||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Queue;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a collection of RemoteAnimationTargets, filtered by different properties.
|
* Holds a collection of RemoteAnimationTargets, filtered by different properties.
|
||||||
*/
|
*/
|
||||||
public class RemoteAnimationTargets {
|
public class RemoteAnimationTargets {
|
||||||
|
|
||||||
private final Queue<SyncRtSurfaceTransactionApplierCompat> mDependentTransactionAppliers =
|
private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>();
|
||||||
new ArrayDeque<>(1);
|
|
||||||
|
|
||||||
public final RemoteAnimationTargetCompat[] unfilteredApps;
|
public final RemoteAnimationTargetCompat[] unfilteredApps;
|
||||||
public final RemoteAnimationTargetCompat[] apps;
|
public final RemoteAnimationTargetCompat[] apps;
|
||||||
@@ -36,6 +33,8 @@ public class RemoteAnimationTargets {
|
|||||||
public final int targetMode;
|
public final int targetMode;
|
||||||
public final boolean hasRecents;
|
public final boolean hasRecents;
|
||||||
|
|
||||||
|
private boolean mReleased = false;
|
||||||
|
|
||||||
public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
|
public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
|
||||||
RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
|
RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
|
||||||
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
|
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
|
||||||
@@ -76,21 +75,65 @@ public class RemoteAnimationTargets {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDependentTransactionApplier(SyncRtSurfaceTransactionApplierCompat delay) {
|
public void addReleaseCheck(ReleaseCheck check) {
|
||||||
mDependentTransactionAppliers.add(delay);
|
mReleaseChecks.add(check);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
SyncRtSurfaceTransactionApplierCompat applier = mDependentTransactionAppliers.poll();
|
if (mReleased) {
|
||||||
if (applier == null) {
|
return;
|
||||||
for (RemoteAnimationTargetCompat target : unfilteredApps) {
|
}
|
||||||
target.release();
|
for (ReleaseCheck check : mReleaseChecks) {
|
||||||
|
if (!check.mCanRelease) {
|
||||||
|
check.addOnSafeToReleaseCallback(this::release);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
for (RemoteAnimationTargetCompat target : wallpapers) {
|
}
|
||||||
target.release();
|
mReleaseChecks.clear();
|
||||||
|
mReleased = true;
|
||||||
|
|
||||||
|
for (RemoteAnimationTargetCompat target : unfilteredApps) {
|
||||||
|
target.release();
|
||||||
|
}
|
||||||
|
for (RemoteAnimationTargetCompat target : wallpapers) {
|
||||||
|
target.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for intercepting surface release method
|
||||||
|
*/
|
||||||
|
public static class ReleaseCheck {
|
||||||
|
|
||||||
|
boolean mCanRelease = false;
|
||||||
|
private Runnable mAfterApplyCallback;
|
||||||
|
|
||||||
|
protected void setCanRelease(boolean canRelease) {
|
||||||
|
mCanRelease = canRelease;
|
||||||
|
if (mCanRelease && mAfterApplyCallback != null) {
|
||||||
|
Runnable r = mAfterApplyCallback;
|
||||||
|
mAfterApplyCallback = null;
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to notify when the surface can safely be released
|
||||||
|
*/
|
||||||
|
void addOnSafeToReleaseCallback(Runnable callback) {
|
||||||
|
if (mCanRelease) {
|
||||||
|
callback.run();
|
||||||
|
} else {
|
||||||
|
if (mAfterApplyCallback == null) {
|
||||||
|
mAfterApplyCallback = callback;
|
||||||
|
} else {
|
||||||
|
final Runnable oldCallback = mAfterApplyCallback;
|
||||||
|
mAfterApplyCallback = () -> {
|
||||||
|
callback.run();
|
||||||
|
oldCallback.run();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
applier.addAfterApplyCallback(this::release);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,6 @@ final class BackGestureTutorialController extends TutorialController {
|
|||||||
super(fragment, tutorialType);
|
super(fragment, tutorialType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void transitToController() {
|
|
||||||
super.transitToController();
|
|
||||||
if (mTutorialType != BACK_NAVIGATION_COMPLETE) {
|
|
||||||
showHandCoachingAnimation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Integer getTitleStringId() {
|
Integer getTitleStringId() {
|
||||||
switch (mTutorialType) {
|
switch (mTutorialType) {
|
||||||
|
|||||||
@@ -280,7 +280,11 @@ public class EdgeBackGesturePanel extends View {
|
|||||||
new SpringForce()
|
new SpringForce()
|
||||||
.setStiffness(SpringForce.STIFFNESS_MEDIUM)
|
.setStiffness(SpringForce.STIFFNESS_MEDIUM)
|
||||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
||||||
mPaint.setColor(context.getColor(R.color.back_arrow_color_dark));
|
int currentNightMode =
|
||||||
|
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
mPaint.setColor(context.getColor(currentNightMode == Configuration.UI_MODE_NIGHT_YES
|
||||||
|
? R.color.back_arrow_color_light
|
||||||
|
: R.color.back_arrow_color_dark));
|
||||||
loadDimens();
|
loadDimens();
|
||||||
updateArrowDirection();
|
updateArrowDirection();
|
||||||
|
|
||||||
|
|||||||
+11
-221
@@ -15,143 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.quickstep.interaction;
|
package com.android.quickstep.interaction;
|
||||||
|
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
|
||||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
|
||||||
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
|
|
||||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.AnimatorSet;
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Insets;
|
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.SurfaceControl;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
import android.view.WindowInsets.Type;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
|
||||||
import com.android.launcher3.InvariantDeviceProfile;
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
|
||||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
|
||||||
import com.android.launcher3.anim.PendingAnimation;
|
|
||||||
import com.android.quickstep.AnimatedFloat;
|
|
||||||
import com.android.quickstep.GestureState;
|
|
||||||
import com.android.quickstep.OverviewComponentObserver;
|
|
||||||
import com.android.quickstep.RecentsAnimationDeviceState;
|
|
||||||
import com.android.quickstep.SwipeUpAnimationLogic;
|
|
||||||
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
|
|
||||||
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
|
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
|
||||||
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
|
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
|
||||||
import com.android.quickstep.util.RectFSpringAnim;
|
|
||||||
import com.android.quickstep.util.TransformParams;
|
|
||||||
import com.android.systemui.shared.system.QuickStepContract;
|
|
||||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
|
||||||
|
|
||||||
/** A {@link TutorialController} for the Home tutorial. */
|
/** A {@link TutorialController} for the Home tutorial. */
|
||||||
@TargetApi(Build.VERSION_CODES.R)
|
@TargetApi(Build.VERSION_CODES.R)
|
||||||
final class HomeGestureTutorialController extends TutorialController {
|
final class HomeGestureTutorialController extends SwipeUpGestureTutorialController {
|
||||||
|
|
||||||
private float mFakeTaskViewRadius;
|
|
||||||
private Rect mFakeTaskViewRect = new Rect();
|
|
||||||
|
|
||||||
private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
|
|
||||||
private RunningWindowAnim mRunningWindowAnim;
|
|
||||||
|
|
||||||
HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
|
HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
|
||||||
super(fragment, tutorialType);
|
super(fragment, tutorialType);
|
||||||
|
|
||||||
RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
|
|
||||||
OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
|
|
||||||
mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
|
|
||||||
new GestureState(observer, -1));
|
|
||||||
observer.onDestroy();
|
|
||||||
deviceState.destroy();
|
|
||||||
|
|
||||||
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
|
|
||||||
.getDeviceProfile(mContext)
|
|
||||||
.copy(mContext);
|
|
||||||
Insets insets = mContext.getSystemService(WindowManager.class)
|
|
||||||
.getCurrentWindowMetrics()
|
|
||||||
.getWindowInsets()
|
|
||||||
.getInsets(Type.systemBars());
|
|
||||||
dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
|
|
||||||
mViewSwipeUpAnimation.initDp(dp);
|
|
||||||
|
|
||||||
mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
|
|
||||||
|
|
||||||
mFakeTaskView.setClipToOutline(true);
|
|
||||||
mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
|
|
||||||
@Override
|
|
||||||
public void getOutline(View view, Outline outline) {
|
|
||||||
outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelRunningAnimation() {
|
|
||||||
if (mRunningWindowAnim != null) {
|
|
||||||
mRunningWindowAnim.cancel();
|
|
||||||
}
|
|
||||||
mRunningWindowAnim = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fades the task view, optionally after animating to a fake Overview. */
|
|
||||||
private void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
|
|
||||||
cancelRunningAnimation();
|
|
||||||
PendingAnimation anim = new PendingAnimation(300);
|
|
||||||
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
|
||||||
mFakeTaskView.setVisibility(View.INVISIBLE);
|
|
||||||
mFakeTaskView.setAlpha(1);
|
|
||||||
mRunningWindowAnim = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (toOverviewFirst) {
|
|
||||||
anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
|
|
||||||
anim.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
|
||||||
PendingAnimation fadeAnim = new PendingAnimation(300);
|
|
||||||
fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
|
||||||
fadeAnim.addListener(resetTaskView);
|
|
||||||
AnimatorSet animset = fadeAnim.buildAnim();
|
|
||||||
animset.setStartDelay(100);
|
|
||||||
animset.start();
|
|
||||||
mRunningWindowAnim = RunningWindowAnim.wrap(animset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
|
||||||
anim.addListener(resetTaskView);
|
|
||||||
}
|
|
||||||
if (onEndRunnable != null) {
|
|
||||||
anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
|
|
||||||
}
|
|
||||||
AnimatorSet animset = anim.buildAnim();
|
|
||||||
animset.start();
|
|
||||||
mRunningWindowAnim = RunningWindowAnim.wrap(animset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void transitToController() {
|
|
||||||
super.transitToController();
|
|
||||||
if (mTutorialType != HOME_NAVIGATION_COMPLETE) {
|
|
||||||
showHandCoachingAnimation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -190,6 +70,14 @@ final class HomeGestureTutorialController extends TutorialController {
|
|||||||
public void onBackGestureAttempted(BackGestureResult result) {
|
public void onBackGestureAttempted(BackGestureResult result) {
|
||||||
switch (mTutorialType) {
|
switch (mTutorialType) {
|
||||||
case HOME_NAVIGATION:
|
case HOME_NAVIGATION:
|
||||||
|
switch (result) {
|
||||||
|
case BACK_COMPLETED_FROM_LEFT:
|
||||||
|
case BACK_COMPLETED_FROM_RIGHT:
|
||||||
|
case BACK_CANCELLED_FROM_LEFT:
|
||||||
|
case BACK_CANCELLED_FROM_RIGHT:
|
||||||
|
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case HOME_NAVIGATION_COMPLETE:
|
case HOME_NAVIGATION_COMPLETE:
|
||||||
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
|
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
|
||||||
@@ -206,17 +94,8 @@ final class HomeGestureTutorialController extends TutorialController {
|
|||||||
case HOME_NAVIGATION:
|
case HOME_NAVIGATION:
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case HOME_GESTURE_COMPLETED: {
|
case HOME_GESTURE_COMPLETED: {
|
||||||
hideFeedback();
|
animateFakeTaskViewHome(finalVelocity, () ->
|
||||||
cancelRunningAnimation();
|
mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE));
|
||||||
hideHandCoachingAnimation();
|
|
||||||
RectFSpringAnim rectAnim =
|
|
||||||
mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
|
|
||||||
// After home animation finishes, fade out and then move to the next screen.
|
|
||||||
rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
|
|
||||||
() -> fadeOutFakeTaskView(false,
|
|
||||||
() -> mTutorialFragment.changeController(
|
|
||||||
HOME_NAVIGATION_COMPLETE))));
|
|
||||||
mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
||||||
@@ -242,93 +121,4 @@ final class HomeGestureTutorialController extends TutorialController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNavBarGestureProgress(@Nullable Float displacement) {
|
|
||||||
if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE) {
|
|
||||||
mFakeTaskView.setVisibility(View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
mFakeTaskView.setVisibility(View.VISIBLE);
|
|
||||||
if (mRunningWindowAnim == null) {
|
|
||||||
mViewSwipeUpAnimation.updateDisplacement(displacement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewSwipeUpAnimation extends SwipeUpAnimationLogic {
|
|
||||||
|
|
||||||
ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
|
|
||||||
GestureState gestureState) {
|
|
||||||
super(context, deviceState, gestureState, new FakeTransformParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDp(DeviceProfile dp) {
|
|
||||||
initTransitionEndpoints(dp);
|
|
||||||
mTaskViewSimulator.setPreviewBounds(
|
|
||||||
new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateFinalShift() {
|
|
||||||
float progress = mCurrentShift.value / mDragLengthFactor;
|
|
||||||
mWindowTransitionController.setPlayFraction(progress);
|
|
||||||
mTaskViewSimulator.apply(mTransformParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedFloat getCurrentShift() {
|
|
||||||
return mCurrentShift;
|
|
||||||
}
|
|
||||||
|
|
||||||
RectFSpringAnim handleSwipeUpToHome(PointF velocity) {
|
|
||||||
PointF velocityPxPerMs = new PointF(velocity.x, velocity.y);
|
|
||||||
float currentShift = mCurrentShift.value;
|
|
||||||
final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
|
|
||||||
* getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
|
|
||||||
float distanceToTravel = (1 - currentShift) * mTransitionDragLength;
|
|
||||||
|
|
||||||
// we want the page's snap velocity to approximately match the velocity at
|
|
||||||
// which the user flings, so we scale the duration by a value near to the
|
|
||||||
// derivative of the scroll interpolator at zero, ie. 2.
|
|
||||||
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
|
||||||
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
|
||||||
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
|
|
||||||
@Override
|
|
||||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
|
||||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public RectF getWindowTargetRect() {
|
|
||||||
int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
|
|
||||||
int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
|
|
||||||
int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
|
|
||||||
return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
|
|
||||||
fakeHomeIconLeft + fakeHomeIconSizePx,
|
|
||||||
fakeHomeIconTop + fakeHomeIconSizePx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
|
|
||||||
windowAnim.start(mContext, velocityPxPerMs);
|
|
||||||
return windowAnim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FakeTransformParams extends TransformParams {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
|
|
||||||
SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
|
|
||||||
proxy.onBuildTargetParams(builder, null, this);
|
|
||||||
return new SurfaceParams[] {builder.build()};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applySurfaceParams(SurfaceParams[] params) {
|
|
||||||
SurfaceParams p = params[0];
|
|
||||||
mFakeTaskView.setAnimationMatrix(p.matrix);
|
|
||||||
mFakeTaskViewRect.set(p.windowCrop);
|
|
||||||
mFakeTaskViewRadius = p.cornerRadius;
|
|
||||||
mFakeTaskView.invalidateOutline();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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.interaction;
|
||||||
|
|
||||||
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
|
||||||
|
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
|
||||||
|
|
||||||
|
/** A {@link TutorialController} for the Overview tutorial. */
|
||||||
|
@TargetApi(Build.VERSION_CODES.R)
|
||||||
|
final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
|
||||||
|
|
||||||
|
OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
|
||||||
|
TutorialType tutorialType) {
|
||||||
|
super(fragment, tutorialType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Integer getTitleStringId() {
|
||||||
|
switch (mTutorialType) {
|
||||||
|
case OVERVIEW_NAVIGATION:
|
||||||
|
return R.string.overview_gesture_tutorial_playground_title;
|
||||||
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
||||||
|
return R.string.gesture_tutorial_confirm_title;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Integer getSubtitleStringId() {
|
||||||
|
if (mTutorialType == TutorialType.OVERVIEW_NAVIGATION) {
|
||||||
|
return R.string.overview_gesture_tutorial_playground_subtitle;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Integer getActionButtonStringId() {
|
||||||
|
if (mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
|
||||||
|
return R.string.gesture_tutorial_action_button_label_done;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onActionButtonClicked(View button) {
|
||||||
|
mTutorialFragment.closeTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackGestureAttempted(BackGestureResult result) {
|
||||||
|
switch (mTutorialType) {
|
||||||
|
case OVERVIEW_NAVIGATION:
|
||||||
|
switch (result) {
|
||||||
|
case BACK_COMPLETED_FROM_LEFT:
|
||||||
|
case BACK_COMPLETED_FROM_RIGHT:
|
||||||
|
case BACK_CANCELLED_FROM_LEFT:
|
||||||
|
case BACK_CANCELLED_FROM_RIGHT:
|
||||||
|
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
||||||
|
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
|
||||||
|
|| result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
|
||||||
|
mTutorialFragment.closeTutorial();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
|
||||||
|
switch (mTutorialType) {
|
||||||
|
case OVERVIEW_NAVIGATION:
|
||||||
|
switch (result) {
|
||||||
|
case HOME_GESTURE_COMPLETED: {
|
||||||
|
animateFakeTaskViewHome(finalVelocity, () ->
|
||||||
|
showFeedback(R.string.overview_gesture_feedback_home_detected));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
||||||
|
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
||||||
|
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
|
||||||
|
break;
|
||||||
|
case OVERVIEW_GESTURE_COMPLETED:
|
||||||
|
fadeOutFakeTaskView(true, () ->
|
||||||
|
mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE));
|
||||||
|
break;
|
||||||
|
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
|
||||||
|
case HOME_OR_OVERVIEW_CANCELLED:
|
||||||
|
fadeOutFakeTaskView(false, null);
|
||||||
|
showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
||||||
|
if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
|
||||||
|
mTutorialFragment.closeTutorial();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.interaction;
|
||||||
|
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.quickstep.interaction.TutorialController.TutorialType;
|
||||||
|
|
||||||
|
/** Shows the Overview gesture interactive tutorial. */
|
||||||
|
public class OverviewGestureTutorialFragment extends TutorialFragment {
|
||||||
|
@Override
|
||||||
|
int getHandAnimationResId() {
|
||||||
|
return R.drawable.overview_gesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
TutorialController createController(TutorialType type) {
|
||||||
|
return new OverviewGestureTutorialController(this, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Class<? extends TutorialController> getControllerClass() {
|
||||||
|
return OverviewGestureTutorialController.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
+246
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* 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.interaction;
|
||||||
|
|
||||||
|
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||||
|
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||||
|
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
|
||||||
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
||||||
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Insets;
|
||||||
|
import android.graphics.Outline;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewOutlineProvider;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.launcher3.DeviceProfile;
|
||||||
|
import com.android.launcher3.InvariantDeviceProfile;
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||||
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
|
import com.android.quickstep.AnimatedFloat;
|
||||||
|
import com.android.quickstep.GestureState;
|
||||||
|
import com.android.quickstep.OverviewComponentObserver;
|
||||||
|
import com.android.quickstep.RecentsAnimationDeviceState;
|
||||||
|
import com.android.quickstep.SwipeUpAnimationLogic;
|
||||||
|
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
|
||||||
|
import com.android.quickstep.util.RectFSpringAnim;
|
||||||
|
import com.android.quickstep.util.TransformParams;
|
||||||
|
import com.android.systemui.shared.system.QuickStepContract;
|
||||||
|
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.R)
|
||||||
|
abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||||
|
private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
|
||||||
|
private float mFakeTaskViewRadius;
|
||||||
|
private Rect mFakeTaskViewRect = new Rect();
|
||||||
|
private RunningWindowAnim mRunningWindowAnim;
|
||||||
|
|
||||||
|
SwipeUpGestureTutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
|
||||||
|
super(tutorialFragment, tutorialType);
|
||||||
|
RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
|
||||||
|
OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
|
||||||
|
mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
|
||||||
|
new GestureState(observer, -1));
|
||||||
|
observer.onDestroy();
|
||||||
|
deviceState.destroy();
|
||||||
|
|
||||||
|
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
|
||||||
|
.getDeviceProfile(mContext)
|
||||||
|
.copy(mContext);
|
||||||
|
Insets insets = mContext.getSystemService(WindowManager.class)
|
||||||
|
.getCurrentWindowMetrics()
|
||||||
|
.getWindowInsets()
|
||||||
|
.getInsets(WindowInsets.Type.systemBars());
|
||||||
|
dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
|
||||||
|
mViewSwipeUpAnimation.initDp(dp);
|
||||||
|
|
||||||
|
mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
|
||||||
|
mFakeTaskView.setClipToOutline(true);
|
||||||
|
mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
|
||||||
|
@Override
|
||||||
|
public void getOutline(View view, Outline outline) {
|
||||||
|
outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelRunningAnimation() {
|
||||||
|
if (mRunningWindowAnim != null) {
|
||||||
|
mRunningWindowAnim.cancel();
|
||||||
|
}
|
||||||
|
mRunningWindowAnim = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fades the task view, optionally after animating to a fake Overview. */
|
||||||
|
void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
|
||||||
|
hideFeedback();
|
||||||
|
hideHandCoachingAnimation();
|
||||||
|
cancelRunningAnimation();
|
||||||
|
PendingAnimation anim = new PendingAnimation(300);
|
||||||
|
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
||||||
|
mFakeTaskView.setVisibility(View.INVISIBLE);
|
||||||
|
mFakeTaskView.setAlpha(1);
|
||||||
|
mRunningWindowAnim = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (toOverviewFirst) {
|
||||||
|
anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
|
||||||
|
anim.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
||||||
|
PendingAnimation fadeAnim = new PendingAnimation(300);
|
||||||
|
fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
||||||
|
fadeAnim.addListener(resetTaskView);
|
||||||
|
AnimatorSet animset = fadeAnim.buildAnim();
|
||||||
|
animset.setStartDelay(100);
|
||||||
|
animset.start();
|
||||||
|
mRunningWindowAnim = RunningWindowAnim.wrap(animset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
||||||
|
anim.addListener(resetTaskView);
|
||||||
|
}
|
||||||
|
if (onEndRunnable != null) {
|
||||||
|
anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
|
||||||
|
}
|
||||||
|
AnimatorSet animset = anim.buildAnim();
|
||||||
|
animset.start();
|
||||||
|
mRunningWindowAnim = RunningWindowAnim.wrap(animset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void animateFakeTaskViewHome(PointF finalVelocity, @Nullable Runnable onEndRunnable) {
|
||||||
|
hideFeedback();
|
||||||
|
hideHandCoachingAnimation();
|
||||||
|
cancelRunningAnimation();
|
||||||
|
RectFSpringAnim rectAnim =
|
||||||
|
mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
|
||||||
|
// After home animation finishes, fade out and run onEndRunnable.
|
||||||
|
rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
|
||||||
|
() -> fadeOutFakeTaskView(false, onEndRunnable)));
|
||||||
|
mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNavBarGestureProgress(@Nullable Float displacement) {
|
||||||
|
if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE
|
||||||
|
|| mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
|
||||||
|
mFakeTaskView.setVisibility(View.INVISIBLE);
|
||||||
|
} else {
|
||||||
|
mFakeTaskView.setVisibility(View.VISIBLE);
|
||||||
|
if (mRunningWindowAnim == null) {
|
||||||
|
mViewSwipeUpAnimation.updateDisplacement(displacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewSwipeUpAnimation extends SwipeUpAnimationLogic {
|
||||||
|
|
||||||
|
ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
|
||||||
|
GestureState gestureState) {
|
||||||
|
super(context, deviceState, gestureState, new FakeTransformParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDp(DeviceProfile dp) {
|
||||||
|
initTransitionEndpoints(dp);
|
||||||
|
mTaskViewSimulator.setPreviewBounds(
|
||||||
|
new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateFinalShift() {
|
||||||
|
float progress = mCurrentShift.value / mDragLengthFactor;
|
||||||
|
mWindowTransitionController.setPlayFraction(progress);
|
||||||
|
mTaskViewSimulator.apply(mTransformParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedFloat getCurrentShift() {
|
||||||
|
return mCurrentShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectFSpringAnim handleSwipeUpToHome(PointF velocity) {
|
||||||
|
PointF velocityPxPerMs = new PointF(velocity.x, velocity.y);
|
||||||
|
float currentShift = mCurrentShift.value;
|
||||||
|
final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
|
||||||
|
* getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
|
||||||
|
float distanceToTravel = (1 - currentShift) * mTransitionDragLength;
|
||||||
|
|
||||||
|
// we want the page's snap velocity to approximately match the velocity at
|
||||||
|
// which the user flings, so we scale the duration by a value near to the
|
||||||
|
// derivative of the scroll interpolator at zero, ie. 2.
|
||||||
|
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
||||||
|
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
||||||
|
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
|
||||||
|
@Override
|
||||||
|
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||||
|
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RectF getWindowTargetRect() {
|
||||||
|
int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
|
||||||
|
int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
|
||||||
|
int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
|
||||||
|
return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
|
||||||
|
fakeHomeIconLeft + fakeHomeIconSizePx,
|
||||||
|
fakeHomeIconTop + fakeHomeIconSizePx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
|
||||||
|
windowAnim.start(mContext, velocityPxPerMs);
|
||||||
|
return windowAnim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeTransformParams extends TransformParams {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
|
||||||
|
SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
|
||||||
|
proxy.onBuildTargetParams(builder, null, this);
|
||||||
|
return new SurfaceParams[] {builder.build()};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applySurfaceParams(SurfaceParams[] params) {
|
||||||
|
SurfaceParams p = params[0];
|
||||||
|
mFakeTaskView.setAnimationMatrix(p.matrix);
|
||||||
|
mFakeTaskViewRect.set(p.windowCrop);
|
||||||
|
mFakeTaskViewRadius = p.cornerRadius;
|
||||||
|
mFakeTaskView.invalidateOutline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,6 +140,9 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
|||||||
void onActionTextButtonClicked(View button) {}
|
void onActionTextButtonClicked(View button) {}
|
||||||
|
|
||||||
void showHandCoachingAnimation() {
|
void showHandCoachingAnimation() {
|
||||||
|
if (isComplete()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
|
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +156,12 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
|||||||
hideFeedback();
|
hideFeedback();
|
||||||
updateTitles();
|
updateTitles();
|
||||||
updateActionButtons();
|
updateActionButtons();
|
||||||
|
|
||||||
|
if (isComplete()) {
|
||||||
|
hideHandCoachingAnimation();
|
||||||
|
} else {
|
||||||
|
showHandCoachingAnimation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTitles() {
|
private void updateTitles() {
|
||||||
@@ -190,12 +199,20 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
|||||||
button.setOnClickListener(listener);
|
button.setOnClickListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isComplete() {
|
||||||
|
return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
|
||||||
|
|| mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
|
||||||
|
|| mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
/** Denotes the type of the tutorial. */
|
/** Denotes the type of the tutorial. */
|
||||||
enum TutorialType {
|
enum TutorialType {
|
||||||
RIGHT_EDGE_BACK_NAVIGATION,
|
RIGHT_EDGE_BACK_NAVIGATION,
|
||||||
LEFT_EDGE_BACK_NAVIGATION,
|
LEFT_EDGE_BACK_NAVIGATION,
|
||||||
BACK_NAVIGATION_COMPLETE,
|
BACK_NAVIGATION_COMPLETE,
|
||||||
HOME_NAVIGATION,
|
HOME_NAVIGATION,
|
||||||
HOME_NAVIGATION_COMPLETE
|
HOME_NAVIGATION_COMPLETE,
|
||||||
|
OVERVIEW_NAVIGATION,
|
||||||
|
OVERVIEW_NAVIGATION_COMPLETE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
|||||||
case HOME_NAVIGATION:
|
case HOME_NAVIGATION:
|
||||||
case HOME_NAVIGATION_COMPLETE:
|
case HOME_NAVIGATION_COMPLETE:
|
||||||
return new HomeGestureTutorialFragment();
|
return new HomeGestureTutorialFragment();
|
||||||
|
case OVERVIEW_NAVIGATION:
|
||||||
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
||||||
|
return new OverviewGestureTutorialFragment();
|
||||||
default:
|
default:
|
||||||
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
|
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ripple android:color="@color/gesture_tutorial_ripple_color"
|
<ripple android:color="@color/gesture_tutorial_ripple_color"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android"/>
|
||||||
<item android:id="@android:id/mask"
|
|
||||||
android:drawable="@color/gesture_tutorial_background_color" />
|
|
||||||
</ripple>
|
|
||||||
@@ -38,14 +38,8 @@
|
|||||||
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
|
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
|
||||||
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
|
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
|
||||||
|
|
||||||
<color name="gesture_tutorial_background_color">#FFFFFFFF</color>
|
|
||||||
<color name="gesture_tutorial_title_color">#FF000000</color>
|
|
||||||
<color name="gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
|
|
||||||
<color name="gesture_tutorial_feedback_color">#FF000000</color>
|
|
||||||
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
|
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
|
||||||
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
|
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
|
||||||
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
|
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
|
||||||
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
|
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -81,7 +81,6 @@
|
|||||||
<item name="folderFillColor">#CDFFFFFF</item>
|
<item name="folderFillColor">#CDFFFFFF</item>
|
||||||
<item name="folderIconBorderColor">#FF80868B</item>
|
<item name="folderIconBorderColor">#FF80868B</item>
|
||||||
<item name="folderTextColor">?attr/workspaceTextColor</item>
|
<item name="folderTextColor">?attr/workspaceTextColor</item>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
|
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ shadows= \
|
|||||||
com.android.launcher3.shadows.ShadowLooperExecutor \
|
com.android.launcher3.shadows.ShadowLooperExecutor \
|
||||||
com.android.launcher3.shadows.ShadowMainThreadInitializedObject \
|
com.android.launcher3.shadows.ShadowMainThreadInitializedObject \
|
||||||
com.android.launcher3.shadows.ShadowOverrides \
|
com.android.launcher3.shadows.ShadowOverrides \
|
||||||
com.android.launcher3.shadows.ShadowSyncRtSurfaceTransactionApplierCompat \
|
com.android.launcher3.shadows.ShadowSurfaceTransactionApplier \
|
||||||
|
|
||||||
application=com.android.launcher3.util.LauncherTestApplication
|
application=com.android.launcher3.util.LauncherTestApplication
|
||||||
+3
-3
@@ -26,11 +26,11 @@ import org.robolectric.annotation.Implements;
|
|||||||
import org.robolectric.annotation.RealObject;
|
import org.robolectric.annotation.RealObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shadow for SyncRtSurfaceTransactionApplierCompat to override default functionality
|
* Shadow for SurfaceTransactionApplier to override default functionality
|
||||||
*/
|
*/
|
||||||
@Implements(className = "com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat",
|
@Implements(className = "com.android.quickstep.util.SurfaceTransactionApplier",
|
||||||
isInAndroidSdk = false)
|
isInAndroidSdk = false)
|
||||||
public class ShadowSyncRtSurfaceTransactionApplierCompat {
|
public class ShadowSurfaceTransactionApplier {
|
||||||
|
|
||||||
@RealObject
|
@RealObject
|
||||||
private Object mRealObject;
|
private Object mRealObject;
|
||||||
@@ -411,6 +411,11 @@ public class LauncherProvider extends ContentProvider {
|
|||||||
Favorites.BACKUP_TABLE_NAME);
|
Favorites.BACKUP_TABLE_NAME);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
case LauncherSettings.Settings.METHOD_REFRESH_HOTSEAT_RESTORE_TABLE: {
|
||||||
|
mOpenHelper.mHotseatRestoreTableExists = tableExists(
|
||||||
|
mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
|
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
|
||||||
final long ts = System.currentTimeMillis();
|
final long ts = System.currentTimeMillis();
|
||||||
if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
|
if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
|
||||||
@@ -609,6 +614,7 @@ public class LauncherProvider extends ContentProvider {
|
|||||||
private int mMaxItemId = -1;
|
private int mMaxItemId = -1;
|
||||||
private int mMaxScreenId = -1;
|
private int mMaxScreenId = -1;
|
||||||
private boolean mBackupTableExists;
|
private boolean mBackupTableExists;
|
||||||
|
private boolean mHotseatRestoreTableExists;
|
||||||
|
|
||||||
static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) {
|
static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) {
|
||||||
return createDatabaseHelper(context, null, forMigration);
|
return createDatabaseHelper(context, null, forMigration);
|
||||||
@@ -633,6 +639,8 @@ public class LauncherProvider extends ContentProvider {
|
|||||||
databaseHelper.mBackupTableExists = tableExists(
|
databaseHelper.mBackupTableExists = tableExists(
|
||||||
databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
|
databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
|
||||||
}
|
}
|
||||||
|
databaseHelper.mHotseatRestoreTableExists = tableExists(
|
||||||
|
databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||||
|
|
||||||
databaseHelper.initIds();
|
databaseHelper.initIds();
|
||||||
return databaseHelper;
|
return databaseHelper;
|
||||||
@@ -679,6 +687,10 @@ public class LauncherProvider extends ContentProvider {
|
|||||||
dropTable(db, Favorites.BACKUP_TABLE_NAME);
|
dropTable(db, Favorites.BACKUP_TABLE_NAME);
|
||||||
mBackupTableExists = false;
|
mBackupTableExists = false;
|
||||||
}
|
}
|
||||||
|
if (mHotseatRestoreTableExists) {
|
||||||
|
dropTable(db, Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||||
|
mHotseatRestoreTableExists = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ public class LauncherSettings {
|
|||||||
*/
|
*/
|
||||||
public static final String BACKUP_TABLE_NAME = "favorites_bakup";
|
public static final String BACKUP_TABLE_NAME = "favorites_bakup";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backup table created when user hotseat is moved to workspace for hybrid hotseat
|
||||||
|
*/
|
||||||
|
public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary table used specifically for grid migrations during wallpaper preview
|
* Temporary table used specifically for grid migrations during wallpaper preview
|
||||||
*/
|
*/
|
||||||
@@ -333,6 +338,8 @@ public class LauncherSettings {
|
|||||||
|
|
||||||
public static final String METHOD_REFRESH_BACKUP_TABLE = "refresh_backup_table";
|
public static final String METHOD_REFRESH_BACKUP_TABLE = "refresh_backup_table";
|
||||||
|
|
||||||
|
public static final String METHOD_REFRESH_HOTSEAT_RESTORE_TABLE = "restore_hotseat_table";
|
||||||
|
|
||||||
public static final String METHOD_RESTORE_BACKUP_TABLE = "restore_backup_table";
|
public static final String METHOD_RESTORE_BACKUP_TABLE = "restore_backup_table";
|
||||||
|
|
||||||
public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";
|
public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.allapps;
|
package com.android.launcher3.allapps;
|
||||||
|
|
||||||
|
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
@@ -56,6 +58,13 @@ public interface SearchUiManager {
|
|||||||
void setContentVisibility(int visibleElements, PropertySetter setter,
|
void setContentVisibility(int visibleElements, PropertySetter setter,
|
||||||
Interpolator interpolator);
|
Interpolator interpolator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the QSB should be visible for the given set of visible elements
|
||||||
|
*/
|
||||||
|
default boolean isQsbVisible(int visibleElements) {
|
||||||
|
return (visibleElements & ALL_APPS_HEADER) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to control how the search UI result should be handled.
|
* Called to control how the search UI result should be handled.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import static android.view.View.MeasureSpec.EXACTLY;
|
|||||||
import static android.view.View.MeasureSpec.getSize;
|
import static android.view.View.MeasureSpec.getSize;
|
||||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
|
|
||||||
import static com.android.launcher3.Utilities.prefixTextWithIcon;
|
import static com.android.launcher3.Utilities.prefixTextWithIcon;
|
||||||
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
|
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
|
||||||
|
|
||||||
@@ -213,7 +212,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
|||||||
@Override
|
@Override
|
||||||
public void setContentVisibility(int visibleElements, PropertySetter setter,
|
public void setContentVisibility(int visibleElements, PropertySetter setter,
|
||||||
Interpolator interpolator) {
|
Interpolator interpolator) {
|
||||||
setter.setViewAlpha(this, (visibleElements & ALL_APPS_HEADER) != 0 ? 1 : 0, interpolator);
|
setter.setViewAlpha(this, isQsbVisible(visibleElements) ? 1 : 0, interpolator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public final class FeatureFlags {
|
|||||||
"Adds localized title and keyword search and ranking");
|
"Adds localized title and keyword search and ranking");
|
||||||
|
|
||||||
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
|
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
|
||||||
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
|
"ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
|
||||||
|
|
||||||
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
|
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
|
||||||
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
|
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
|
||||||
|
|||||||
@@ -96,13 +96,23 @@ public class StatsLogManager implements ResourceBasedOverride {
|
|||||||
+ "the icon onto 'Uninstall' button in the target bar")
|
+ "the icon onto 'Uninstall' button in the target bar")
|
||||||
LAUNCHER_ITEM_UNINSTALL_CANCELLED(470),
|
LAUNCHER_ITEM_UNINSTALL_CANCELLED(470),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User tapped or long pressed on the task icon(aka package icon) "
|
||||||
|
+ "from overview to open task menu.")
|
||||||
|
LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS(517),
|
||||||
|
|
||||||
@UiEvent(doc = "User opened package specific widgets list by tapping on widgets system "
|
@UiEvent(doc = "User opened package specific widgets list by tapping on widgets system "
|
||||||
+ "shortcut within longpress popup window.")
|
+ "shortcut within longpress popup window.")
|
||||||
LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514),
|
LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514),
|
||||||
|
|
||||||
@UiEvent(doc = "User opened app info of the package by tapping on appinfo system shortcut "
|
@UiEvent(doc = "User opened app info of the package by tapping on appinfo system shortcut "
|
||||||
+ "within longpress popup window.")
|
+ "within longpress popup window.")
|
||||||
LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515);
|
LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User tapped on split screen icon on a task menu.")
|
||||||
|
LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP(518),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User tapped on free form icon on a task menu.")
|
||||||
|
LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519);
|
||||||
// ADD MORE
|
// ADD MORE
|
||||||
|
|
||||||
private final int mId;
|
private final int mId;
|
||||||
|
|||||||
@@ -127,6 +127,32 @@ public class GridBackupTable {
|
|||||||
return mRestoredHotseatSize;
|
return mRestoredHotseatSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new table and populates with copy of Favorites.TABLE_NAME
|
||||||
|
*/
|
||||||
|
public void createCustomBackupTable(String tableName) {
|
||||||
|
long profileId = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
|
||||||
|
Process.myUserHandle());
|
||||||
|
copyTable(mDb, Favorites.TABLE_NAME, tableName, profileId);
|
||||||
|
encodeDBProperties(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Restores the contents of a custom table to Favorites.TABLE_NAME
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void restoreFromCustomBackupTable(String tableName, boolean dropAfterUse) {
|
||||||
|
if (!tableExists(mDb, tableName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
|
||||||
|
Process.myUserHandle());
|
||||||
|
copyTable(mDb, tableName, Favorites.TABLE_NAME, userSerial);
|
||||||
|
if (dropAfterUse) {
|
||||||
|
dropTable(mDb, tableName);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Copy valid grid entries from one table to another.
|
* Copy valid grid entries from one table to another.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -237,6 +237,15 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
sandboxCategory.addPreference(launchHomeTutorialPreference);
|
sandboxCategory.addPreference(launchHomeTutorialPreference);
|
||||||
|
Preference launchOverviewTutorialPreference = new Preference(context);
|
||||||
|
launchOverviewTutorialPreference.setKey("launchOverviewTutorial");
|
||||||
|
launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial");
|
||||||
|
launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture");
|
||||||
|
launchOverviewTutorialPreference.setOnPreferenceClickListener(preference -> {
|
||||||
|
startActivity(launchSandboxIntent.putExtra("tutorial_type", "OVERVIEW_NAVIGATION"));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
sandboxCategory.addPreference(launchOverviewTutorialPreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toName(String action) {
|
private String toName(String action) {
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ public class StateAnimationConfig {
|
|||||||
ANIM_ALL_APPS_FADE,
|
ANIM_ALL_APPS_FADE,
|
||||||
ANIM_OVERVIEW_SCRIM_FADE,
|
ANIM_OVERVIEW_SCRIM_FADE,
|
||||||
ANIM_ALL_APPS_HEADER_FADE,
|
ANIM_ALL_APPS_HEADER_FADE,
|
||||||
ANIM_OVERVIEW_MODAL
|
ANIM_OVERVIEW_MODAL,
|
||||||
|
ANIM_DEPTH,
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface AnimType {}
|
public @interface AnimType {}
|
||||||
@@ -87,8 +88,9 @@ public class StateAnimationConfig {
|
|||||||
public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
|
public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
|
||||||
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
|
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
|
||||||
public static final int ANIM_OVERVIEW_MODAL = 13;
|
public static final int ANIM_OVERVIEW_MODAL = 13;
|
||||||
|
public static final int ANIM_DEPTH = 14;
|
||||||
|
|
||||||
private static final int ANIM_TYPES_COUNT = 14;
|
private static final int ANIM_TYPES_COUNT = 15;
|
||||||
|
|
||||||
private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
|
private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
|
||||||
|
|
||||||
|
|||||||
@@ -101,4 +101,5 @@ public final class TestProtocol {
|
|||||||
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
|
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
|
||||||
public static final String PAUSE_NOT_DETECTED = "b/139891609";
|
public static final String PAUSE_NOT_DETECTED = "b/139891609";
|
||||||
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
|
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
|
||||||
|
public static final String NO_SWIPE_TO_HOME = "b/158017601";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user