Merging ub-launcher3-qt-dev, build 5456758
Test: Manual Bug:111142970 Icon display blur in all apps page Bug:114136250 Have a more spartan RecentsActivity on android go Bug:122609330 Update PIP animation for swiping up to home Bug:123985787 Respect dialogCornerRadius for all apps / widgets / settings / shortcut menu / dwb / task / overview (everything) Bug:126587956 Create an app to use with Launcher testing Bug:126606858 In multiwindow mode, not able to switch between recent apps. Bug:127766994 Gray app icons disappeared after completing cable transfer for a while Bug:127987071 Create a proper contract for specifying default Launcher Layout Bug:129033091 [Q-Preview] I would like the ability to swipe up anywhere on my screen to open up the app li. Bug:129297464 [Gesture Nav] Exclude edges from most Launcher / Overview states. Bug:129434166 Lab-only flake: drag to workspace doesn't happen Bug:129746879 [Q-Preview] Quick search bar overlaying other app Bug:129874298 Show different string (Wallpaper vs Style & Wallpaper) on Settings depending on device type Bug:129947426 nexus launcher crash observed randomly during device boot up(NPE:Attempt to invoke virtual method 'android.app.ActivityManager$RunningTaskInfo com.android.systemui.shared.system.ActivityManagerWrapper.getRunningTask(int)' on a null object reference) Bug:129976669 Implement returning to home from Widgets in 0-button mode Bug:130027168 Can't tap in nav region on home screen Bug:130151609 Some tests in MultiDisplaySystemDecorationTests.java failing in pre-submit Bug:130182878 Pixel launcher crashes on secondary display Bug:130225926 Cannot unpin app while in gesture nav Bug:130245920 Icons disappear from launcher when selected Bug:130272454 [C1/B1] Message app crash when opening a video MMS. Change-Id: I18aa35d2c75deaf5149358d96d4e1d7f26de2f02
This commit is contained in:
@@ -42,6 +42,9 @@ public final class TaskActionController {
|
||||
* @param viewHolder the task view holder to launch
|
||||
*/
|
||||
public void launchTask(TaskHolder viewHolder) {
|
||||
if (viewHolder.getTask() == null) {
|
||||
return;
|
||||
}
|
||||
TaskItemView itemView = (TaskItemView) (viewHolder.itemView);
|
||||
View v = itemView.getThumbnailView();
|
||||
int left = 0;
|
||||
@@ -60,6 +63,9 @@ public final class TaskActionController {
|
||||
* @param viewHolder the task view holder to remove
|
||||
*/
|
||||
public void removeTask(TaskHolder viewHolder) {
|
||||
if (viewHolder.getTask() == null) {
|
||||
return;
|
||||
}
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
Task task = viewHolder.getTask();
|
||||
ActivityManagerWrapper.getInstance().removeTask(task.key.id);
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.android.quickstep.views.TaskItemView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Recycler view adapter that dynamically inflates and binds {@link TaskHolder} instances with the
|
||||
@@ -40,6 +41,7 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
private final TaskListLoader mLoader;
|
||||
private final ArrayMap<Integer, TaskItemView> mTaskIdToViewMap = new ArrayMap<>();
|
||||
private TaskActionController mTaskActionController;
|
||||
private boolean mIsShowingLoadingUi;
|
||||
|
||||
public TaskAdapter(@NonNull TaskListLoader loader) {
|
||||
mLoader = loader;
|
||||
@@ -49,6 +51,18 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
mTaskActionController = taskActionController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all positions in the task adapter to loading views, binding new views if necessary.
|
||||
* This changes the task adapter's view of the data, so the appropriate notify events should be
|
||||
* called in addition to this method to reflect the changes.
|
||||
*
|
||||
* @param isShowingLoadingUi true to bind loading task views to all positions, false to return
|
||||
* to the real data
|
||||
*/
|
||||
public void setIsShowingLoadingUi(boolean isShowingLoadingUi) {
|
||||
mIsShowingLoadingUi = isShowingLoadingUi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get task item view for a given task id if it's attached to the view.
|
||||
*
|
||||
@@ -70,6 +84,10 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(TaskHolder holder, int position) {
|
||||
if (mIsShowingLoadingUi) {
|
||||
holder.bindEmptyUi();
|
||||
return;
|
||||
}
|
||||
List<Task> tasks = mLoader.getCurrentTaskList();
|
||||
if (position >= tasks.size()) {
|
||||
// Task list has updated.
|
||||
@@ -79,13 +97,13 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
holder.bindTask(task);
|
||||
mLoader.loadTaskIconAndLabel(task, () -> {
|
||||
// Ensure holder still has the same task.
|
||||
if (task.equals(holder.getTask())) {
|
||||
if (Objects.equals(task, holder.getTask())) {
|
||||
holder.getTaskItemView().setIcon(task.icon);
|
||||
holder.getTaskItemView().setLabel(task.titleDescription);
|
||||
}
|
||||
});
|
||||
mLoader.loadTaskThumbnail(task, () -> {
|
||||
if (task.equals(holder.getTask())) {
|
||||
if (Objects.equals(task, holder.getTask())) {
|
||||
holder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
|
||||
}
|
||||
});
|
||||
@@ -93,16 +111,27 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull TaskHolder holder) {
|
||||
if (holder.getTask() == null) {
|
||||
return;
|
||||
}
|
||||
mTaskIdToViewMap.put(holder.getTask().key.id, (TaskItemView) holder.itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull TaskHolder holder) {
|
||||
if (holder.getTask() == null) {
|
||||
return;
|
||||
}
|
||||
mTaskIdToViewMap.remove(holder.getTask().key.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
|
||||
if (mIsShowingLoadingUi) {
|
||||
// Show loading version of all items.
|
||||
return MAX_TASKS_TO_DISPLAY;
|
||||
} else {
|
||||
return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.android.quickstep.views.TaskItemView;
|
||||
@@ -50,11 +50,23 @@ public final class TaskHolder extends ViewHolder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task currently bound to this view
|
||||
* Bind a generic empty UI to the holder to make it clear that the item is loading/unbound and
|
||||
* should not be expected to react to user input.
|
||||
*/
|
||||
public void bindEmptyUi() {
|
||||
mTask = null;
|
||||
// TODO: Set the task view to a loading, empty UI.
|
||||
// Temporarily using the one below for visual confirmation but should be swapped out to new
|
||||
// UI later.
|
||||
mTaskItemView.resetTaskItemView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task currently bound to this view. May be null if task holder is in a loading state.
|
||||
*
|
||||
* @return the current task
|
||||
*/
|
||||
public @NonNull Task getTask() {
|
||||
public @Nullable Task getTask() {
|
||||
return mTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,17 +67,27 @@ public final class TaskListLoader {
|
||||
return Collections.unmodifiableList(mTaskList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the loader needs to load data to be up to date. This can return true if the
|
||||
* task list is already up to date OR there is already a load in progress for the task list to
|
||||
* become up to date.
|
||||
*
|
||||
* @return true if already up to date or load in progress, false otherwise
|
||||
*/
|
||||
public boolean needsToLoad() {
|
||||
return !mRecentsModel.isTaskListValid(mTaskListChangeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the most recent tasks and updates the task list asynchronously. This call does not
|
||||
* provide guarantees the task content (icon, thumbnail, label) are loaded but will fill in
|
||||
* what it has. May run the callback immediately if there have been no changes in the task
|
||||
* list.
|
||||
* list since the start of the last load.
|
||||
*
|
||||
* @param onLoadedCallback callback to run when task list is loaded
|
||||
*/
|
||||
public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onLoadedCallback) {
|
||||
if (mRecentsModel.isTaskListValid(mTaskListChangeId)) {
|
||||
// Current task list is already up to date. No need to update.
|
||||
if (!needsToLoad()) {
|
||||
if (onLoadedCallback != null) {
|
||||
onLoadedCallback.accept(mTaskList);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ public class TouchInteractionService extends Service {
|
||||
ISystemUiProxy iSystemUiProxy = ISystemUiProxy.Stub
|
||||
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
|
||||
mRecentsModel.setSystemUiProxy(iSystemUiProxy);
|
||||
mRecentsModel.onInitializeSystemUI(bundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,10 @@ import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationSet;
|
||||
import android.view.animation.LayoutAnimationController;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -69,6 +73,8 @@ public final class IconRecentsView extends FrameLayout {
|
||||
}
|
||||
};
|
||||
private static final long CROSSFADE_DURATION = 300;
|
||||
private static final long LAYOUT_ITEM_ANIMATE_IN_DURATION = 150;
|
||||
private static final long LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN = 40;
|
||||
private static final long ITEM_ANIMATE_OUT_DURATION = 150;
|
||||
private static final long ITEM_ANIMATE_OUT_DELAY_BETWEEN = 40;
|
||||
private static final float ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO = .25f;
|
||||
@@ -84,6 +90,7 @@ public final class IconRecentsView extends FrameLayout {
|
||||
private final TaskListLoader mTaskLoader;
|
||||
private final TaskAdapter mTaskAdapter;
|
||||
private final TaskActionController mTaskActionController;
|
||||
private final LayoutAnimationController mLayoutAnimation;
|
||||
|
||||
private RecentsToActivityHelper mActivityHelper;
|
||||
private RecyclerView mTaskRecyclerView;
|
||||
@@ -99,6 +106,7 @@ public final class IconRecentsView extends FrameLayout {
|
||||
mTaskAdapter = new TaskAdapter(mTaskLoader);
|
||||
mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
|
||||
mTaskAdapter.setActionController(mTaskActionController);
|
||||
mLayoutAnimation = createLayoutAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,6 +120,7 @@ public final class IconRecentsView extends FrameLayout {
|
||||
ItemTouchHelper helper = new ItemTouchHelper(
|
||||
new TaskSwipeCallback(mTaskActionController));
|
||||
helper.attachToRecyclerView(mTaskRecyclerView);
|
||||
mTaskRecyclerView.setLayoutAnimation(mLayoutAnimation);
|
||||
|
||||
mEmptyView = findViewById(R.id.recent_task_empty_view);
|
||||
mContentView = findViewById(R.id.recent_task_content_view);
|
||||
@@ -131,7 +140,6 @@ public final class IconRecentsView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
@@ -157,10 +165,17 @@ public final class IconRecentsView extends FrameLayout {
|
||||
* becomes visible.
|
||||
*/
|
||||
public void onBeginTransitionToOverview() {
|
||||
mTaskRecyclerView.scheduleLayoutAnimation();
|
||||
|
||||
// Load any task changes
|
||||
if (!mTaskLoader.needsToLoad()) {
|
||||
return;
|
||||
}
|
||||
mTaskAdapter.setIsShowingLoadingUi(true);
|
||||
mTaskAdapter.notifyDataSetChanged();
|
||||
mTaskLoader.loadTaskList(tasks -> {
|
||||
// TODO: Put up some loading UI while task content is loading. May have to do something
|
||||
// smarter when animating from app to overview.
|
||||
mTaskAdapter.setIsShowingLoadingUi(false);
|
||||
// TODO: Animate the loading UI out and the loaded data in.
|
||||
mTaskAdapter.notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
@@ -322,4 +337,18 @@ public final class IconRecentsView extends FrameLayout {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static LayoutAnimationController createLayoutAnimation() {
|
||||
AnimationSet anim = new AnimationSet(false /* shareInterpolator */);
|
||||
|
||||
Animation alphaAnim = new AlphaAnimation(0, 1);
|
||||
alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION);
|
||||
anim.addAnimation(alphaAnim);
|
||||
|
||||
LayoutAnimationController layoutAnim = new LayoutAnimationController(anim);
|
||||
layoutAnim.setDelay(
|
||||
(float) LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN / LAYOUT_ITEM_ANIMATE_IN_DURATION);
|
||||
|
||||
return layoutAnim;
|
||||
}
|
||||
}
|
||||
|
||||
-8
@@ -75,12 +75,4 @@ public class BackgroundAppState extends OverviewState {
|
||||
return new ScaleAndTranslation(scale, 0f, 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVisibleElements(Launcher launcher) {
|
||||
if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
|
||||
return super.getVisibleElements(launcher);
|
||||
}
|
||||
// Hide shelf content (e.g. QSB) because we fade it in when swiping up.
|
||||
return ALL_APPS_HEADER_EXTRA;
|
||||
}
|
||||
}
|
||||
|
||||
+143
-59
@@ -15,74 +15,131 @@
|
||||
*/
|
||||
package com.android.launcher3.uioverrides.touchcontrollers;
|
||||
|
||||
import static android.view.View.TRANSLATION_X;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.AnimationConfig;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.AbstractStateChangeTouchController;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Command;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Handles swiping up on the nav bar to go home from overview or all apps.
|
||||
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
|
||||
*/
|
||||
public class NavBarToHomeTouchController extends AbstractStateChangeTouchController {
|
||||
public class NavBarToHomeTouchController implements TouchController, SwipeDetector.Listener {
|
||||
|
||||
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final SwipeDetector mSwipeDetector;
|
||||
private final float mPullbackDistance;
|
||||
|
||||
private boolean mNoIntercept;
|
||||
private LauncherState mStartState;
|
||||
private LauncherState mEndState = NORMAL;
|
||||
private AnimatorPlaybackController mCurrentAnimation;
|
||||
|
||||
public NavBarToHomeTouchController(Launcher launcher) {
|
||||
super(launcher, SwipeDetector.VERTICAL);
|
||||
mLauncher = launcher;
|
||||
mSwipeDetector = new SwipeDetector(mLauncher, this, SwipeDetector.VERTICAL);
|
||||
mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canInterceptTouch(MotionEvent ev) {
|
||||
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
|
||||
return cameFromNavBar && (mLauncher.isInState(OVERVIEW) || mLauncher.isInState(ALL_APPS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
|
||||
return isDragTowardPositive ? NORMAL : fromState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float initCurrentAnimation(int animComponents) {
|
||||
long accuracy = (long) (getShiftRange() * 2);
|
||||
final AnimatorSet anim;
|
||||
if (mFromState == OVERVIEW) {
|
||||
anim = new AnimatorSet();
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
float pullbackDistance = recentsView.getPaddingStart() / 2;
|
||||
if (!recentsView.isRtl()) {
|
||||
pullbackDistance = -pullbackDistance;
|
||||
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mStartState = mLauncher.getStateManager().getState();
|
||||
mNoIntercept = !canInterceptTouch(ev);
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
anim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X, pullbackDistance));
|
||||
anim.setInterpolator(PULLBACK_INTERPOLATOR);
|
||||
} else { // if (mFromState == ALL_APPS)
|
||||
mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
|
||||
}
|
||||
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
onControllerTouchEvent(ev);
|
||||
return mSwipeDetector.isDraggingOrSettling();
|
||||
}
|
||||
|
||||
private boolean canInterceptTouch(MotionEvent ev) {
|
||||
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
|
||||
if (!cameFromNavBar) {
|
||||
return false;
|
||||
}
|
||||
if (mStartState == OVERVIEW || mStartState == ALL_APPS) {
|
||||
return true;
|
||||
}
|
||||
if (!mLauncher.hasWindowFocus()) {
|
||||
return true;
|
||||
}
|
||||
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onControllerTouchEvent(MotionEvent ev) {
|
||||
return mSwipeDetector.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private float getShiftRange() {
|
||||
return mLauncher.getDeviceProfile().heightPx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
initCurrentAnimation();
|
||||
}
|
||||
|
||||
private void initCurrentAnimation() {
|
||||
long accuracy = (long) (getShiftRange() * 2);
|
||||
final AnimatorSet anim = new AnimatorSet();
|
||||
if (mStartState == OVERVIEW) {
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
float pullbackDist = mPullbackDistance;
|
||||
if (!recentsView.isRtl()) {
|
||||
pullbackDist = -pullbackDist;
|
||||
}
|
||||
Animator pullback = ObjectAnimator.ofFloat(recentsView, TRANSLATION_X, pullbackDist);
|
||||
pullback.setInterpolator(PULLBACK_INTERPOLATOR);
|
||||
anim.play(pullback);
|
||||
} else if (mStartState == ALL_APPS) {
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
|
||||
final float pullbackDistance = mLauncher.getDeviceProfile().allAppsIconSizePx / 2;
|
||||
Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
|
||||
-pullbackDistance / allAppsController.getShiftRange());
|
||||
-mPullbackDistance / allAppsController.getShiftRange());
|
||||
allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR);
|
||||
builder.play(allAppsProgress);
|
||||
// Slightly fade out all apps content to further distinguish from scrolling.
|
||||
@@ -90,52 +147,79 @@ public class NavBarToHomeTouchController extends AbstractStateChangeTouchControl
|
||||
.mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
|
||||
AnimationConfig config = new AnimationConfig();
|
||||
config.duration = accuracy;
|
||||
allAppsController.setAlphas(mToState.getVisibleElements(mLauncher), config, builder);
|
||||
anim = builder.build();
|
||||
allAppsController.setAlphas(mEndState.getVisibleElements(mLauncher), config, builder);
|
||||
anim.play(builder.build());
|
||||
}
|
||||
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
|
||||
if (topView != null) {
|
||||
Animator hintCloseAnim = topView.createHintCloseAnim(mPullbackDistance);
|
||||
if (hintCloseAnim != null) {
|
||||
hintCloseAnim.setInterpolator(PULLBACK_INTERPOLATOR);
|
||||
anim.play(hintCloseAnim);
|
||||
}
|
||||
}
|
||||
anim.setDuration(accuracy);
|
||||
mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy, this::clearState);
|
||||
return -1 / getShiftRange();
|
||||
}
|
||||
|
||||
private void clearState() {
|
||||
mCurrentAnimation = null;
|
||||
mSwipeDetector.finishedScrolling();
|
||||
mSwipeDetector.setDetectableScrollConditions(0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
super.onDragStart(start);
|
||||
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
|
||||
public boolean onDrag(float displacement) {
|
||||
// Only allow swipe up.
|
||||
displacement = Math.min(0, displacement);
|
||||
float progress = Utilities.getProgress(displacement, 0, getShiftRange());
|
||||
mCurrentAnimation.setPlayFraction(progress);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
|
||||
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(
|
||||
mCurrentAnimation.getProgressFraction());
|
||||
if (interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || velocity < 0 && fling) {
|
||||
mLauncher.getStateManager().goToState(mToState, true,
|
||||
() -> onSwipeInteractionCompleted(mToState, logAction));
|
||||
float progress = mCurrentAnimation.getProgressFraction();
|
||||
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress);
|
||||
boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS
|
||||
|| (velocity < 0 && fling);
|
||||
if (success) {
|
||||
mLauncher.getStateManager().goToState(mEndState, true,
|
||||
() -> onSwipeInteractionCompleted(mEndState));
|
||||
if (mStartState != mEndState) {
|
||||
logStateChange(mStartState.containerType, logAction);
|
||||
}
|
||||
AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
|
||||
if (topOpenView != null) {
|
||||
AbstractFloatingView.closeAllOpenViews(mLauncher);
|
||||
logStateChange(topOpenView.getLogContainerType(), logAction);
|
||||
}
|
||||
} else {
|
||||
// Quickly return to the state we came from (we didn't move far).
|
||||
AnimatorPlaybackController anim = mLauncher.getStateManager()
|
||||
.createAnimationToNewWorkspace(mFromState, 80);
|
||||
anim.setEndAction(() -> onSwipeInteractionCompleted(mFromState, logAction));
|
||||
anim.start();
|
||||
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
|
||||
anim.setFloatValues(progress, 0);
|
||||
anim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
onSwipeInteractionCompleted(mStartState);
|
||||
}
|
||||
});
|
||||
anim.setDuration(80).start();
|
||||
}
|
||||
mCurrentAnimation.dispatchOnCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDirectionForLog() {
|
||||
return LauncherLogProto.Action.Direction.UP;
|
||||
private void onSwipeInteractionCompleted(LauncherState targetState) {
|
||||
clearState();
|
||||
mLauncher.getStateManager().goToState(targetState, false /* animated */);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
|
||||
LauncherState toState) {
|
||||
// We don't want to create an atomic animation to/from overview.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLogContainerTypeForNormalState() {
|
||||
return LauncherLogProto.ContainerType.NAVBAR;
|
||||
private void logStateChange(int startContainerType, int logAction) {
|
||||
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
|
||||
LauncherLogProto.Action.Direction.UP,
|
||||
LauncherLogProto.ContainerType.NAVBAR,
|
||||
startContainerType,
|
||||
mEndState.containerType,
|
||||
mLauncher.getWorkspace().getCurrentPage());
|
||||
}
|
||||
}
|
||||
|
||||
+5
-23
@@ -23,7 +23,6 @@ import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -44,11 +43,8 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherInitListener;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -220,7 +216,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
: mShelfState == ShelfAnimState.PEEK
|
||||
? shelfPeekingProgress
|
||||
: shelfOverviewProgress;
|
||||
mShelfAnim = createShelfProgressAnim(activity, toProgress);
|
||||
mShelfAnim = createShelfAnim(activity, toProgress);
|
||||
mShelfAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
@@ -238,10 +234,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
LauncherState fromState, long transitionLength,
|
||||
Consumer<AnimatorPlaybackController> callback) {
|
||||
LauncherState endState = OVERVIEW;
|
||||
DeviceProfile dp = activity.getDeviceProfile();
|
||||
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
|
||||
if (wasVisible && fromState != BACKGROUND_APP) {
|
||||
// If a translucent app was launched fom launcher, animate launcher states.
|
||||
DeviceProfile dp = activity.getDeviceProfile();
|
||||
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
|
||||
callback.accept(activity.getStateManager()
|
||||
.createAnimationToNewWorkspace(fromState, endState, accuracy));
|
||||
return;
|
||||
@@ -254,11 +250,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
if (!activity.getDeviceProfile().isVerticalBarLayout()
|
||||
&& SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
|
||||
// Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
|
||||
Animator shiftAnim = createShelfProgressAnim(activity,
|
||||
Animator shiftAnim = createShelfAnim(activity,
|
||||
fromState.getVerticalProgress(activity),
|
||||
endState.getVerticalProgress(activity));
|
||||
anim.play(shiftAnim);
|
||||
anim.play(createShelfAlphaAnim(activity, endState, accuracy));
|
||||
}
|
||||
playScaleDownAnim(anim, activity, endState);
|
||||
|
||||
@@ -275,7 +270,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
callback.accept(controller);
|
||||
}
|
||||
|
||||
private Animator createShelfProgressAnim(Launcher activity, float ... progressValues) {
|
||||
private Animator createShelfAnim(Launcher activity, float ... progressValues) {
|
||||
Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
|
||||
"allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(),
|
||||
SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
|
||||
@@ -283,19 +278,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
return shiftAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Very quickly fade the alpha of shelf content.
|
||||
*/
|
||||
private Animator createShelfAlphaAnim(Launcher activity, LauncherState toState, long accuracy) {
|
||||
AllAppsTransitionController allAppsController = activity.getAllAppsController();
|
||||
AnimatorSetBuilder animBuilder = new AnimatorSetBuilder();
|
||||
animBuilder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, DEACCEL_3);
|
||||
LauncherStateManager.AnimationConfig config = new LauncherStateManager.AnimationConfig();
|
||||
config.duration = accuracy;
|
||||
allAppsController.setAlphas(toState.getVisibleElements(activity), config, animBuilder);
|
||||
return animBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale down recents from the center task being full screen to being in overview.
|
||||
*/
|
||||
|
||||
@@ -136,17 +136,13 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
private void sendEvent(MotionEvent ev) {
|
||||
if (mInvalidated || !mTarget.verifyTouchDispatch(this, ev)) {
|
||||
mInvalidated = true;
|
||||
if (mInvalidated) {
|
||||
return;
|
||||
}
|
||||
int flags = ev.getEdgeFlags();
|
||||
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
|
||||
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
|
||||
if (ev.getAction() == ACTION_DOWN) {
|
||||
mTarget.onInterceptTouchEvent(ev);
|
||||
}
|
||||
mTarget.onTouchEvent(ev);
|
||||
mInvalidated = !mTarget.dispatchTouchEvent(this, ev);
|
||||
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
||||
ev.setEdgeFlags(flags);
|
||||
}
|
||||
|
||||
@@ -290,6 +290,10 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
if (sysUiProxy == null) {
|
||||
return null;
|
||||
}
|
||||
if (SysUINavigationMode.getMode(activity) == SysUINavigationMode.Mode.NO_BUTTON) {
|
||||
// TODO(b/130225926): Temporarily disable pinning while gesture nav is enabled
|
||||
return null;
|
||||
}
|
||||
if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-2
@@ -101,7 +101,6 @@ public class TouchInteractionService extends Service implements
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
|
||||
runWhenUserUnlocked(() -> {
|
||||
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
|
||||
mRecentsModel.onInitializeSystemUI(bundle);
|
||||
mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
|
||||
});
|
||||
}
|
||||
@@ -426,7 +425,7 @@ public class TouchInteractionService extends Service implements
|
||||
|
||||
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
|
||||
// TODO: this makes a binder call every touch down. we should move to a listener pattern.
|
||||
if (mKM.isDeviceLocked()) {
|
||||
if (!mIsUserUnlocked || mKM.isDeviceLocked()) {
|
||||
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched
|
||||
// while device is locked even after exiting direct boot mode (e.g. camera).
|
||||
return new DeviceLockedInputConsumer(this);
|
||||
|
||||
+6
-6
@@ -16,6 +16,8 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
@@ -33,6 +35,7 @@ import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -97,12 +100,9 @@ public class ClipAnimationHelper {
|
||||
(t, a1) -> a1;
|
||||
|
||||
public ClipAnimationHelper(Context context) {
|
||||
mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
|
||||
mSupportsRoundedCornersOnWindows = RecentsModel.INSTANCE.get(context)
|
||||
.supportsRoundedCornersOnWindows();
|
||||
int taskCornerRadiusRes = mSupportsRoundedCornersOnWindows ?
|
||||
R.dimen.task_corner_radius : R.dimen.task_corner_radius_small;
|
||||
mTaskCornerRadius = context.getResources().getDimension(taskCornerRadiusRes);
|
||||
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
|
||||
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
|
||||
mTaskCornerRadius = Themes.getDialogCornerRadius(context);
|
||||
}
|
||||
|
||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.TaskSystemShortcut;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
@@ -270,7 +271,7 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||
}
|
||||
|
||||
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
|
||||
float radius = getResources().getDimension(R.dimen.task_corner_radius);
|
||||
float radius = Themes.getDialogCornerRadius(getContext());
|
||||
Rect fromRect = new Rect(0, 0, getWidth(), 0);
|
||||
Rect toRect = new Rect(0, 0, getWidth(), getHeight());
|
||||
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
|
||||
|
||||
+3
-3
@@ -46,11 +46,11 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
/**
|
||||
* A task in the Recents view.
|
||||
@@ -108,7 +108,7 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
|
||||
mCornerRadius = Themes.getDialogCornerRadius(context);
|
||||
mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
|
||||
mPaint.setFilterBitmap(true);
|
||||
mBackgroundPaint.setColor(Color.WHITE);
|
||||
@@ -116,7 +116,7 @@ public class TaskThumbnailView extends View {
|
||||
mDimmingPaintAfterClearing.setColor(Color.BLACK);
|
||||
mActivity = BaseActivity.fromContext(context);
|
||||
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
|
||||
mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
|
||||
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
|
||||
}
|
||||
|
||||
public void bind(Task task) {
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewPool.Reusable;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskIconCache;
|
||||
@@ -195,7 +196,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
fromContext(context).getStatsLogManager().logTaskLaunch(getRecentsView(),
|
||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||
});
|
||||
setOutlineProvider(new TaskOutlineProvider(getResources()));
|
||||
setOutlineProvider(new TaskOutlineProvider(context, getResources()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -513,9 +514,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private final int mMarginTop;
|
||||
private final float mRadius;
|
||||
|
||||
TaskOutlineProvider(Resources res) {
|
||||
TaskOutlineProvider(Context context, Resources res) {
|
||||
mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
||||
mRadius = res.getDimension(R.dimen.task_corner_radius);
|
||||
mRadius = Themes.getDialogCornerRadius(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="#E61A73E8" />
|
||||
<corners android:radius="@dimen/task_corner_radius" />
|
||||
<corners android:radius="?android:attr/dialogCornerRadius" />
|
||||
</shape>
|
||||
@@ -28,8 +28,8 @@
|
||||
<!-- Background -->
|
||||
<shape>
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/task_corner_radius"
|
||||
android:topRightRadius="@dimen/task_corner_radius"
|
||||
android:topLeftRadius="?android:attr/dialogCornerRadius"
|
||||
android:topRightRadius="?android:attr/dialogCornerRadius"
|
||||
android:bottomLeftRadius="0dp"
|
||||
android:bottomRightRadius="0dp" />
|
||||
<solid android:color="?attr/popupColorPrimary" />
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
<dimen name="task_thumbnail_top_margin">24dp</dimen>
|
||||
<dimen name="task_thumbnail_half_top_margin">12dp</dimen>
|
||||
<dimen name="task_thumbnail_icon_size">48dp</dimen>
|
||||
<dimen name="task_corner_radius">8dp</dimen>
|
||||
<!-- For screens without rounded corners -->
|
||||
<dimen name="task_corner_radius_small">2dp</dimen>
|
||||
|
||||
<dimen name="recents_page_spacing">10dp</dimen>
|
||||
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
|
||||
<dimen name="overview_peek_distance">32dp</dimen>
|
||||
@@ -61,11 +59,13 @@
|
||||
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
|
||||
<dimen name="multi_window_task_divider_size">10dp</dimen>
|
||||
|
||||
<dimen name="shelf_surface_radius">16dp</dimen>
|
||||
<!-- same as vertical_drag_handle_size -->
|
||||
<dimen name="shelf_surface_offset">24dp</dimen>
|
||||
|
||||
<!-- Assistant Gestures -->
|
||||
<dimen name="gestures_assistant_size">28dp</dimen>
|
||||
<dimen name="gestures_assistant_drag_threshold">70dp</dimen>
|
||||
|
||||
<!-- Distance to move elements when swiping up to go home from launcher -->
|
||||
<dimen name="home_pullback_distance">28dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -31,6 +31,7 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
@@ -63,12 +64,12 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
||||
import com.android.systemui.shared.system.ActivityCompat;
|
||||
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
|
||||
@@ -473,6 +474,10 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
});
|
||||
|
||||
float shapeRevealDuration = APP_LAUNCH_DURATION * SHAPE_PROGRESS_DURATION;
|
||||
|
||||
final float windowRadius = mDeviceProfile.isMultiWindowMode
|
||||
? 0 : getWindowCornerRadius(mLauncher.getResources());
|
||||
|
||||
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
FloatProp mDx = new FloatProp(0, dX, 0, xDuration, AGGRESSIVE_EASE);
|
||||
FloatProp mDy = new FloatProp(0, dY, 0, yDuration, AGGRESSIVE_EASE);
|
||||
@@ -514,13 +519,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
float transX0 = temp.left - offsetX;
|
||||
float transY0 = temp.top - offsetY;
|
||||
|
||||
float windowRadius = 0;
|
||||
if (!mDeviceProfile.isMultiWindowMode &&
|
||||
RecentsModel.INSTANCE.get(mLauncher).supportsRoundedCornersOnWindows()) {
|
||||
windowRadius = RecentsModel.INSTANCE.get(mLauncher)
|
||||
.getWindowCornerRadius();
|
||||
}
|
||||
|
||||
SurfaceParams[] params = new SurfaceParams[targets.length];
|
||||
for (int i = targets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = targets[i];
|
||||
@@ -651,7 +649,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
|
||||
float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
|
||||
RecentsModel.INSTANCE.get(mLauncher).getWindowCornerRadius();
|
||||
QuickStepContract.getWindowCornerRadius(mLauncher.getResources());
|
||||
unlockAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
@@ -677,8 +675,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
Matrix matrix = new Matrix();
|
||||
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
int duration = CLOSING_TRANSITION_DURATION_MS;
|
||||
float windowCornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
|
||||
RecentsModel.INSTANCE.get(mLauncher).getWindowCornerRadius();
|
||||
float windowCornerRadius = mDeviceProfile.isMultiWindowMode
|
||||
? 0 : getWindowCornerRadius(mLauncher.getResources());
|
||||
closingAnimator.setDuration(duration);
|
||||
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.quickstep.OverviewInteractionState;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -87,6 +86,9 @@ public class UiFactory extends RecentsUiFactory {
|
||||
}
|
||||
OverviewInteractionState.INSTANCE.get(launcher)
|
||||
.setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
|
||||
if (launcher != null && launcher.getDragLayer() != null) {
|
||||
launcher.getDragLayer().setDisallowBackGesture(shouldBackButtonBeHidden);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onCreate(Launcher launcher) {
|
||||
|
||||
+3
-2
@@ -44,7 +44,6 @@ import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.AbstractStateChangeTouchController;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.PortraitOverviewStateTouchHelper;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -114,8 +113,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If we are swiping to all apps instead of overview, allow it from anywhere.
|
||||
boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
|
||||
// For all other states, only listen if the event originated below the hotseat height
|
||||
if (!isTouchOverHotseat(mLauncher, ev)) {
|
||||
if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -62,9 +63,6 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
private final TaskIconCache mIconCache;
|
||||
private final TaskThumbnailCache mThumbnailCache;
|
||||
|
||||
private float mWindowCornerRadius = 0;
|
||||
private boolean mSupportsRoundedCornersOnWindows;
|
||||
|
||||
private RecentsModel(Context context) {
|
||||
mContext = context;
|
||||
HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache",
|
||||
@@ -76,12 +74,6 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
|
||||
}
|
||||
|
||||
public void onInitializeSystemUI(Bundle params) {
|
||||
mWindowCornerRadius = params.getFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, 0);
|
||||
mSupportsRoundedCornersOnWindows =
|
||||
params.getBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, false);
|
||||
}
|
||||
|
||||
public TaskIconCache getIconCache() {
|
||||
return mIconCache;
|
||||
}
|
||||
@@ -182,14 +174,6 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
return mSystemUiProxy;
|
||||
}
|
||||
|
||||
public float getWindowCornerRadius() {
|
||||
return mWindowCornerRadius;
|
||||
}
|
||||
|
||||
public boolean supportsRoundedCornersOnWindows() {
|
||||
return mSupportsRoundedCornersOnWindows;
|
||||
}
|
||||
|
||||
public void onTrimMemory(int level) {
|
||||
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
|
||||
mThumbnailCache.getHighResLoadingState().setVisible(false);
|
||||
|
||||
@@ -27,8 +27,6 @@ import androidx.annotation.IntDef;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
@@ -118,14 +116,10 @@ public class LayoutUtils {
|
||||
}
|
||||
|
||||
public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
|
||||
if (SysUINavigationMode.getMode(context) == Mode.NO_BUTTON) {
|
||||
// Track the bottom of the window rather than the top of the shelf.
|
||||
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
|
||||
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
|
||||
R.dimen.task_card_vert_space);
|
||||
return shelfHeight + spaceBetweenShelfAndRecents;
|
||||
}
|
||||
// Start from a third of bottom inset to provide some shelf overlap.
|
||||
return dp.hotseatBarSizePx + dp.getInsets().bottom / 3 - dp.edgeMarginPx * 2;
|
||||
// Track the bottom of the window.
|
||||
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
|
||||
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
|
||||
R.dimen.task_card_vert_space);
|
||||
return shelfHeight + spaceBetweenShelfAndRecents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
|
||||
// cover the whole screen
|
||||
private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
|
||||
|
||||
// Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public
|
||||
private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f;
|
||||
|
||||
// In transposed layout, we simply draw a flat color.
|
||||
private boolean mDrawingFlatColor;
|
||||
|
||||
@@ -87,7 +90,7 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
|
||||
mMaxScrimAlpha = Math.round(OVERVIEW.getWorkspaceScrimAlpha(mLauncher) * 255);
|
||||
|
||||
mEndAlpha = Color.alpha(mEndScrim);
|
||||
mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
|
||||
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
|
||||
|
||||
@@ -32,7 +32,6 @@ import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.tapl.TestHelpers;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.rules.TestRule;
|
||||
@@ -78,9 +77,9 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
final Context context = getInstrumentation().getContext();
|
||||
final String prevOverlayPkg = QuickStepContract.isGesturalMode(context)
|
||||
final String prevOverlayPkg = LauncherInstrumentation.isGesturalMode(context)
|
||||
? NAV_BAR_MODE_GESTURAL_OVERLAY
|
||||
: QuickStepContract.isSwipeUpMode(context)
|
||||
: LauncherInstrumentation.isSwipeUpMode(context)
|
||||
? NAV_BAR_MODE_2BUTTON_OVERLAY
|
||||
: NAV_BAR_MODE_3BUTTON_OVERLAY;
|
||||
final LauncherInstrumentation.NavigationModel originalMode =
|
||||
@@ -150,4 +149,4 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 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.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?android:attr/colorPrimary" />
|
||||
<corners android:radius="?android:attr/dialogCornerRadius" />
|
||||
</shape>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 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.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?android:attr/colorPrimary" />
|
||||
<corners
|
||||
android:topLeftRadius="?android:attr/dialogCornerRadius"
|
||||
android:topRightRadius="?android:attr/dialogCornerRadius"
|
||||
android:bottomLeftRadius="0dp"
|
||||
android:bottomRightRadius="0dp"
|
||||
/>
|
||||
</shape>
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tryk to gange, og hold fingeren nede for at vælge en widget eller bruge tilpassede handlinger."</string>
|
||||
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
|
||||
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk og hold fingeren nede for at placere manuelt"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk og hold nede for at placere manuelt"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"Tilføj automatisk"</string>
|
||||
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
|
||||
<string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"വിജറ്റ് തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
|
||||
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
|
||||
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"സ്വമേധയാ സ്ഥാപിക്കുന്നതിന് സ്പർശിച്ചുപിടിക്കുക"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"നേരിട്ട് സ്ഥാപിക്കുന്നതിന് സ്പർശിച്ചുപിടിക്കുക"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"സ്വയമേവ ചേർക്കുക"</string>
|
||||
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ആപ്പുകൾ തിരയുക"</string>
|
||||
<string name="all_apps_loading_message" msgid="5813968043155271636">"ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."</string>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
|
||||
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"अापोआप जोडा"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"आपोआप जोडा"</string>
|
||||
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
|
||||
<string name="all_apps_loading_message" msgid="5813968043155271636">"अॅप्स लोड करत आहे…"</string>
|
||||
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
|
||||
<string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
|
||||
<string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
|
||||
<string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
|
||||
<string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
|
||||
<string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
|
||||
<string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
|
||||
<string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"విడ్జెట్ను ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి, ఉంచండి."</string>
|
||||
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
|
||||
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d వెడల్పు X %2$d ఎత్తు"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"మాన్యువల్గా ఉంచడానికి నొక్కి &amp పట్టుకోండి"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"స్వయంచాలకంగా జోడించు"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"మాన్యువల్గా ఉంచడానికి నొక్కి, పట్టుకోండి"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"ఆటోమేటిక్గా జోడించు"</string>
|
||||
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"అప్లికేషన్లను శోధించండి"</string>
|
||||
<string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్లను లోడ్ చేస్తోంది…"</string>
|
||||
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"</string>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"วิดเจ็ตของ <xliff:g id="NAME">%1$s</xliff:g>"</string>
|
||||
<string name="widgets_list" msgid="796804551140113767">"รายการวิดเจ็ต"</string>
|
||||
<string name="widgets_list_closed" msgid="6141506579418771922">"ปิดรายการวิดเจ็ตแล้ว"</string>
|
||||
<string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าแรก"</string>
|
||||
<string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าจอหลัก"</string>
|
||||
<string name="action_move_here" msgid="2170188780612570250">"ย้ายรายการมาที่นี่"</string>
|
||||
<string name="item_added_to_workspace" msgid="4211073925752213539">"เพิ่มรายการไปยังหน้าจอหลักแล้ว"</string>
|
||||
<string name="item_removed" msgid="851119963877842327">"นำออกรายการออกแล้ว"</string>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"I-double tap nang matagal upang pumili ng widget o gumamit ng mga custom na pagkilos."</string>
|
||||
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
|
||||
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal upang manual na ilagay"</string>
|
||||
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal para manual na ilagay"</string>
|
||||
<string name="place_automatically" msgid="8064208734425456485">"Awtomatikong idagdag"</string>
|
||||
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
|
||||
<string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
|
||||
|
||||
<!-- Hotseat/all-apps scrim -->
|
||||
<dimen name="all_apps_scrim_radius">8dp</dimen>
|
||||
<dimen name="all_apps_scrim_margin">8dp</dimen>
|
||||
<dimen name="all_apps_scrim_blur">4dp</dimen>
|
||||
<dimen name="vertical_drag_handle_size">24dp</dimen>
|
||||
<dimen name="vertical_drag_handle_overlap_workspace">0dp</dimen>
|
||||
@@ -237,4 +235,8 @@
|
||||
<!-- Hints -->
|
||||
<dimen name="chip_hint_height">26dp</dimen>
|
||||
<dimen name="chip_hint_bottom_margin">194dp</dimen>
|
||||
|
||||
<!-- Theming related -->
|
||||
<dimen name="default_dialog_corner_radius">8dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
|
||||
<item name="folderDotColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
|
||||
<item name="loadingIconColor">#FFF</item>
|
||||
<item name="loadingIconColor">#CCFFFFFF</item>
|
||||
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
@@ -82,7 +82,7 @@
|
||||
<item name="folderDotColor">#FF464646</item>
|
||||
<item name="folderIconBorderColor">#FF80868B</item>
|
||||
<item name="isMainColorDark">true</item>
|
||||
<item name="loadingIconColor">#000</item>
|
||||
<item name="loadingIconColor">#99FFFFFF</item>
|
||||
</style>
|
||||
|
||||
<style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
|
||||
|
||||
@@ -26,7 +26,6 @@ public class FlagOverrideSampleTest {
|
||||
@Test
|
||||
public void withFlagOn() {
|
||||
assertTrue(FeatureFlags.EXAMPLE_FLAG.get());
|
||||
assertFalse(FeatureFlags.STYLE_WALLPAPER.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@ package com.android.launcher3;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
@@ -30,7 +32,11 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
@@ -38,8 +44,6 @@ import com.android.launcher3.views.BaseDragLayer;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
/**
|
||||
* Base class for a View which shows a floating UI on top of the launcher UI.
|
||||
*/
|
||||
@@ -124,8 +128,20 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
|
||||
|
||||
protected abstract void handleClose(boolean animate);
|
||||
|
||||
/**
|
||||
* Creates a user-controlled animation to hint that the view will be closed if completed.
|
||||
* @param distanceToMove The max distance that elements should move from their starting point.
|
||||
*/
|
||||
public @Nullable Animator createHintCloseAnim(float distanceToMove) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void logActionCommand(int command);
|
||||
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.DEFAULT_CONTAINERTYPE;
|
||||
}
|
||||
|
||||
public final boolean isOpen() {
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Layout parsing code for auto installs layout
|
||||
@@ -76,12 +77,8 @@ public class AutoInstallsLayout {
|
||||
if (customizationApkInfo == null) {
|
||||
return null;
|
||||
}
|
||||
return get(context, customizationApkInfo.first, customizationApkInfo.second,
|
||||
appWidgetHost, callback);
|
||||
}
|
||||
|
||||
static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
|
||||
AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
|
||||
String pkg = customizationApkInfo.first;
|
||||
Resources targetRes = customizationApkInfo.second;
|
||||
InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
|
||||
|
||||
// Try with grid size and hotseat count
|
||||
@@ -114,7 +111,7 @@ public class AutoInstallsLayout {
|
||||
|
||||
// Object Tags
|
||||
private static final String TAG_INCLUDE = "include";
|
||||
private static final String TAG_WORKSPACE = "workspace";
|
||||
public static final String TAG_WORKSPACE = "workspace";
|
||||
private static final String TAG_APP_ICON = "appicon";
|
||||
private static final String TAG_AUTO_INSTALL = "autoinstall";
|
||||
private static final String TAG_FOLDER = "folder";
|
||||
@@ -156,7 +153,7 @@ public class AutoInstallsLayout {
|
||||
|
||||
protected final PackageManager mPackageManager;
|
||||
protected final Resources mSourceRes;
|
||||
protected final int mLayoutId;
|
||||
protected final Supplier<XmlPullParser> mInitialLayoutSupplier;
|
||||
|
||||
private final InvariantDeviceProfile mIdp;
|
||||
private final int mRowCount;
|
||||
@@ -171,6 +168,12 @@ public class AutoInstallsLayout {
|
||||
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
|
||||
LayoutParserCallback callback, Resources res,
|
||||
int layoutId, String rootTag) {
|
||||
this(context, appWidgetHost, callback, res, () -> res.getXml(layoutId), rootTag);
|
||||
}
|
||||
|
||||
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
|
||||
LayoutParserCallback callback, Resources res,
|
||||
Supplier<XmlPullParser> initialLayoutSupplier, String rootTag) {
|
||||
mContext = context;
|
||||
mAppWidgetHost = appWidgetHost;
|
||||
mCallback = callback;
|
||||
@@ -180,7 +183,7 @@ public class AutoInstallsLayout {
|
||||
mRootTag = rootTag;
|
||||
|
||||
mSourceRes = res;
|
||||
mLayoutId = layoutId;
|
||||
mInitialLayoutSupplier = initialLayoutSupplier;
|
||||
|
||||
mIdp = LauncherAppState.getIDP(context);
|
||||
mRowCount = mIdp.numRows;
|
||||
@@ -193,9 +196,9 @@ public class AutoInstallsLayout {
|
||||
public int loadLayout(SQLiteDatabase db, IntArray screenIds) {
|
||||
mDb = db;
|
||||
try {
|
||||
return parseLayout(mLayoutId, screenIds);
|
||||
return parseLayout(mInitialLayoutSupplier.get(), screenIds);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error parsing layout: " + e);
|
||||
Log.e(TAG, "Error parsing layout: ", e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -203,9 +206,8 @@ public class AutoInstallsLayout {
|
||||
/**
|
||||
* Parses the layout and returns the number of elements added on the homescreen.
|
||||
*/
|
||||
protected int parseLayout(int layoutId, IntArray screenIds)
|
||||
protected int parseLayout(XmlPullParser parser, IntArray screenIds)
|
||||
throws XmlPullParserException, IOException {
|
||||
XmlPullParser parser = mSourceRes.getXml(layoutId);
|
||||
beginDocument(parser, mRootTag);
|
||||
final int depth = parser.getDepth();
|
||||
int type;
|
||||
@@ -248,7 +250,7 @@ public class AutoInstallsLayout {
|
||||
final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
|
||||
if (resId != 0) {
|
||||
// recursively load some more favorites, why not?
|
||||
return parseLayout(resId, screenIds);
|
||||
return parseLayout(mSourceRes.getXml(resId), screenIds);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,20 @@ public class CheckLongPressHelper {
|
||||
|
||||
class CheckForLongPress implements Runnable {
|
||||
public void run() {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"CheckForLongPress1");
|
||||
}
|
||||
if ((mView.getParent() != null) && mView.hasWindowFocus()
|
||||
&& !mHasPerformedLongPress) {
|
||||
boolean handled;
|
||||
if (mListener != null) {
|
||||
handled = mListener.onLongClick(mView);
|
||||
} else {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"CheckForLongPress2");
|
||||
}
|
||||
handled = mView.performLongClick();
|
||||
}
|
||||
if (handled) {
|
||||
@@ -73,11 +81,20 @@ public class CheckLongPressHelper {
|
||||
}
|
||||
mView.postDelayed(mPendingCheckForLongPress,
|
||||
(long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor));
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"postCheckForLongPress: " + ViewConfiguration.getLongPressTimeout() + " "
|
||||
+ mLongPressTimeoutFactor);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelLongPress() {
|
||||
mHasPerformedLongPress = false;
|
||||
if (mPendingCheckForLongPress != null) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"cancelLongPress");
|
||||
}
|
||||
mView.removeCallbacks(mPendingCheckForLongPress);
|
||||
mPendingCheckForLongPress = null;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
@@ -98,4 +99,10 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta
|
||||
setLayoutParams(lp);
|
||||
InsettableFrameLayout.dispatchInsets(this, insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// Don't let if follow through to workspace
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -974,7 +974,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mDropTargetBar.setup(mDragController);
|
||||
|
||||
mAllAppsController.setupViews(mAppsView);
|
||||
mHotseat.setOnInterceptTouchListener(mWorkspace::onInterceptHotseatTouch);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.content.Intent;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
@@ -51,8 +52,10 @@ import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
@@ -63,15 +66,21 @@ import com.android.launcher3.model.DbDowngradeHelper;
|
||||
import com.android.launcher3.provider.LauncherDbUtils;
|
||||
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
|
||||
import com.android.launcher3.provider.RestoreDbTask;
|
||||
import com.android.launcher3.util.IOUtils;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.NoLocaleSQLiteHelper;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -93,8 +102,6 @@ public class LauncherProvider extends ContentProvider {
|
||||
|
||||
static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
|
||||
|
||||
private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
|
||||
|
||||
private final ChangeListenerWrapper mListenerWrapper = new ChangeListenerWrapper();
|
||||
private Handler mListenerHandler;
|
||||
|
||||
@@ -505,25 +512,40 @@ public class LauncherProvider extends ContentProvider {
|
||||
*/
|
||||
private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
|
||||
Context ctx = getContext();
|
||||
UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
|
||||
Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
|
||||
if (bundle == null) {
|
||||
InvariantDeviceProfile grid = LauncherAppState.getIDP(ctx);
|
||||
|
||||
String authority = Settings.Secure.getString(ctx.getContentResolver(),
|
||||
"launcher3.layout.provider");
|
||||
if (TextUtils.isEmpty(authority)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
|
||||
if (packageName != null) {
|
||||
try {
|
||||
Resources targetResources = ctx.getPackageManager()
|
||||
.getResourcesForApplication(packageName);
|
||||
return AutoInstallsLayout.get(ctx, packageName, targetResources,
|
||||
widgetHost, mOpenHelper);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "Target package for restricted profile not found", e);
|
||||
return null;
|
||||
}
|
||||
ProviderInfo pi = ctx.getPackageManager().resolveContentProvider(authority, 0);
|
||||
if (pi == null) {
|
||||
Log.e(TAG, "No provider found for authority " + authority);
|
||||
return null;
|
||||
}
|
||||
Uri uri = new Uri.Builder().scheme("content").authority(authority).path("launcher_layout")
|
||||
.appendQueryParameter("version", "1")
|
||||
.appendQueryParameter("gridWidth", Integer.toString(grid.numColumns))
|
||||
.appendQueryParameter("gridHeight", Integer.toString(grid.numRows))
|
||||
.appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons))
|
||||
.build();
|
||||
|
||||
try (InputStream in = ctx.getContentResolver().openInputStream(uri)) {
|
||||
// Read the full xml so that we fail early in case of any IO error.
|
||||
String layout = new String(IOUtils.toByteArray(in));
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new StringReader(layout));
|
||||
|
||||
Log.d(TAG, "Loading layout from " + authority);
|
||||
return new AutoInstallsLayout(ctx, widgetHost, mOpenHelper,
|
||||
ctx.getPackageManager().getResourcesForApplication(pi.applicationInfo),
|
||||
() -> parser, AutoInstallsLayout.TAG_WORKSPACE);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting layout stream from: " + authority , e);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
|
||||
|
||||
@@ -133,9 +133,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
@Thunk int mPageIndicatorViewId;
|
||||
protected T mPageIndicator;
|
||||
|
||||
// Convenience/caching
|
||||
private static final Rect sTmpRect = new Rect();
|
||||
|
||||
protected final Rect mInsets = new Rect();
|
||||
protected boolean mIsRtl;
|
||||
|
||||
@@ -805,12 +802,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
|
||||
/** Returns whether x and y originated within the buffered viewport */
|
||||
private boolean isTouchPointInViewportWithBuffer(float x, float y) {
|
||||
sTmpRect.set(-getMeasuredWidth() / 2, 0, 3 * getMeasuredWidth() / 2, getMeasuredHeight());
|
||||
return sTmpRect.contains((int) x, (int) y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
/*
|
||||
@@ -876,7 +867,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
pageEndTransition();
|
||||
}
|
||||
} else {
|
||||
mIsBeingDragged = isTouchPointInViewportWithBuffer(mDownMotionX, mDownMotionY);
|
||||
mIsBeingDragged = true;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -917,13 +908,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) return;
|
||||
|
||||
// Disallow scrolling if we started the gesture from outside the viewport
|
||||
final float x = ev.getX(pointerIndex);
|
||||
final float y = ev.getY(pointerIndex);
|
||||
if (!isTouchPointInViewportWithBuffer(x, y)) return;
|
||||
|
||||
final int xDiff = (int) Math.abs(x - mLastMotionX);
|
||||
|
||||
final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
|
||||
boolean xMoved = xDiff > touchSlop;
|
||||
|
||||
|
||||
@@ -475,13 +475,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
super.onViewAdded(child);
|
||||
}
|
||||
|
||||
protected boolean onInterceptHotseatTouch(View v, MotionEvent ev) {
|
||||
// We don't want any clicks to go through to the hotseat unless the workspace is in
|
||||
// the normal state or an accessible drag is in progress.
|
||||
return !workspaceIconsCanBeDragged()
|
||||
&& !mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and binds the first page
|
||||
* @param qsb an existing qsb to recycle or null.
|
||||
|
||||
@@ -90,10 +90,6 @@ abstract class BaseFlags {
|
||||
// trying to make them fit the orientation the device is in.
|
||||
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
|
||||
|
||||
public static final ToggleableGlobalSettingsFlag STYLE_WALLPAPER
|
||||
= new ToggleableGlobalSettingsFlag("STYLE_WALLPAPER", false,
|
||||
"Direct users to the new ThemePicker based WallpaperPicker");
|
||||
|
||||
/**
|
||||
* Feature flag to handle define config changes dynamically instead of killing the process.
|
||||
*/
|
||||
|
||||
@@ -24,10 +24,12 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -43,6 +45,7 @@ import com.android.launcher3.DropTargetBar;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
@@ -54,6 +57,8 @@ import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A ViewGroup that coordinates dragging across its descendants
|
||||
@@ -68,6 +73,9 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public static final int ANIMATION_END_DISAPPEAR = 0;
|
||||
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
|
||||
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
|
||||
@Thunk DragController mDragController;
|
||||
|
||||
// Variables relating to animation of views after drop
|
||||
@@ -86,6 +94,8 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
private final ViewGroupFocusHelper mFocusIndicatorHelper;
|
||||
private final WorkspaceAndHotseatScrim mScrim;
|
||||
|
||||
private boolean mDisallowBackGesture;
|
||||
|
||||
/**
|
||||
* Used to create a new DragLayer from XML.
|
||||
*
|
||||
@@ -552,6 +562,24 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
mScrim.onInsetsChanged(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
|
||||
setDisallowBackGesture(mDisallowBackGesture);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public void setDisallowBackGesture(boolean disallowBackGesture) {
|
||||
if (!Utilities.ATLEAST_Q) {
|
||||
return;
|
||||
}
|
||||
mDisallowBackGesture = disallowBackGesture;
|
||||
setSystemGestureExclusionRects(mDisallowBackGesture
|
||||
? SYSTEM_GESTURE_EXCLUSION_RECT
|
||||
: Collections.emptyList());
|
||||
}
|
||||
|
||||
public WorkspaceAndHotseatScrim getScrim() {
|
||||
return mScrim;
|
||||
}
|
||||
|
||||
@@ -1406,7 +1406,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
@Override
|
||||
public void logActionCommand(int command) {
|
||||
mLauncher.getUserEventDispatcher().logActionCommand(
|
||||
command, getFolderIcon(), ContainerType.FOLDER);
|
||||
command, getFolderIcon(), getLogContainerType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.FOLDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.graphics;
|
||||
|
||||
import static androidx.core.graphics.ColorUtils.compositeColors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@@ -47,7 +49,8 @@ public class PlaceHolderIconDrawable extends FastBitmapDrawable {
|
||||
super(b, iconColor);
|
||||
|
||||
mProgressPath = progressPath;
|
||||
mPaint.setColor(Themes.getAttrColor(context, R.attr.loadingIconColor));
|
||||
mPaint.setColor(compositeColors(
|
||||
Themes.getAttrColor(context, R.attr.loadingIconColor), iconColor));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -425,7 +425,8 @@ public class LoaderTask implements Runnable {
|
||||
} else if (installingPkgs.containsKey(targetPkg)) {
|
||||
// App restore has started. Update the flag
|
||||
c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED;
|
||||
c.updater().commit();
|
||||
c.updater().put(LauncherSettings.Favorites.RESTORED,
|
||||
c.restoreFlag).commit();
|
||||
} else {
|
||||
c.markDeleted("Unrestored app removed: " + targetPkg);
|
||||
continue;
|
||||
|
||||
@@ -82,7 +82,7 @@ public abstract class ArrowPopup extends AbstractFloatingView {
|
||||
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
|
||||
mOutlineRadius = Themes.getDialogCornerRadius(context);
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mIsRtl = Utilities.isRtl(getResources());
|
||||
|
||||
|
||||
@@ -157,7 +157,12 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
|
||||
@Override
|
||||
public void logActionCommand(int command) {
|
||||
mLauncher.getUserEventDispatcher().logActionCommand(
|
||||
command, mOriginalIcon, ContainerType.DEEPSHORTCUTS);
|
||||
command, mOriginalIcon, getLogContainerType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.DEEPSHORTCUTS;
|
||||
}
|
||||
|
||||
public OnClickListener getItemClickListener() {
|
||||
|
||||
@@ -25,11 +25,25 @@ import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* Various utility methods associated with theming.
|
||||
*/
|
||||
public class Themes {
|
||||
|
||||
public static float getDialogCornerRadius(Context context) {
|
||||
return getDimension(context, android.R.attr.dialogCornerRadius,
|
||||
context.getResources().getDimension(R.dimen.default_dialog_corner_radius));
|
||||
}
|
||||
|
||||
public static float getDimension(Context context, int attr, float defaultValue) {
|
||||
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
|
||||
float value = ta.getDimension(0, defaultValue);
|
||||
ta.recycle();
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int getColorAccent(Context context) {
|
||||
return getAttrColor(context, android.R.attr.colorAccent);
|
||||
}
|
||||
|
||||
@@ -223,14 +223,18 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
return verifyTouchDispatch(this, ev) && super.dispatchTouchEvent(ev);
|
||||
return dispatchTouchEvent(this, ev);
|
||||
}
|
||||
|
||||
public boolean dispatchTouchEvent(Object caller, MotionEvent ev) {
|
||||
return verifyTouchDispatch(caller, ev) && super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@param caller} is allowed to dispatch {@param ev} on this view,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
|
||||
private boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
|
||||
int action = ev.getAction();
|
||||
if (action == ACTION_DOWN) {
|
||||
if (mCurrentTouchOwner != null) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
@@ -28,8 +30,7 @@ import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
|
||||
public class BottomUserEducationView extends AbstractSlideInView implements Insettable {
|
||||
|
||||
@@ -70,6 +71,11 @@ public class BottomUserEducationView extends AbstractSlideInView implements Inse
|
||||
// Since this is on-boarding popup, it is not a user controlled action.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.TIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOfType(int type) {
|
||||
return (type & TYPE_ON_BOARD_POPUP) != 0;
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
@@ -73,6 +74,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
private static final Rect sTmpRect = new Rect();
|
||||
|
||||
private Runnable mEndRunnable;
|
||||
private CancellationSignal mLoadIconSignal;
|
||||
|
||||
private final int mBlurSizeOutline;
|
||||
|
||||
@@ -153,6 +155,9 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
if (mLoadIconSignal != null) {
|
||||
mLoadIconSignal.cancel();
|
||||
}
|
||||
if (mEndRunnable != null) {
|
||||
mEndRunnable.run();
|
||||
} else {
|
||||
@@ -186,7 +191,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
|
||||
@WorkerThread
|
||||
private void getIcon(Launcher launcher, View v, ItemInfo info, boolean isOpening,
|
||||
Runnable onIconLoadedRunnable) {
|
||||
Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
|
||||
final LayoutParams lp = (LayoutParams) getLayoutParams();
|
||||
Drawable drawable = null;
|
||||
boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
|
||||
@@ -290,7 +295,9 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
setBackground(finalDrawable);
|
||||
}
|
||||
|
||||
onIconLoadedRunnable.run();
|
||||
if (!loadIconSignal.isCanceled()) {
|
||||
onIconLoadedRunnable.run();
|
||||
}
|
||||
invalidate();
|
||||
invalidateOutline();
|
||||
});
|
||||
@@ -386,6 +393,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
// Get the drawable on the background thread
|
||||
// Must be called after matchPositionOf so that we know what size to load.
|
||||
if (originalView.getTag() instanceof ItemInfo) {
|
||||
view.mLoadIconSignal = new CancellationSignal();
|
||||
Runnable onIconLoaded = () -> {
|
||||
// Delay swapping views until the icon is loaded to prevent a flash.
|
||||
view.setVisibility(VISIBLE);
|
||||
@@ -393,9 +401,10 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
originalView.setVisibility(INVISIBLE);
|
||||
}
|
||||
};
|
||||
CancellationSignal loadIconSignal = view.mLoadIconSignal;
|
||||
new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
|
||||
view.getIcon(launcher, originalView, (ItemInfo) originalView.getTag(), isOpening,
|
||||
onIconLoaded);
|
||||
onIconLoaded, loadIconSignal);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -461,6 +470,10 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
setScaleY(1);
|
||||
setAlpha(1);
|
||||
setBackground(null);
|
||||
if (mLoadIconSignal != null) {
|
||||
mLoadIconSignal.cancel();
|
||||
}
|
||||
mLoadIconSignal = null;
|
||||
mEndRunnable = null;
|
||||
mIsAdaptiveIcon = false;
|
||||
mForeground = null;
|
||||
|
||||
@@ -152,7 +152,7 @@ public class OptionsPopupView extends ArrowPopup
|
||||
RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
|
||||
|
||||
ArrayList<OptionItem> options = new ArrayList<>();
|
||||
int res = FeatureFlags.STYLE_WALLPAPER.get() && existsStyleWallpapers(launcher) ?
|
||||
int res = existsStyleWallpapers(launcher) ?
|
||||
R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
|
||||
options.add(new OptionItem(res, R.drawable.ic_wallpaper,
|
||||
ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
|
||||
@@ -210,7 +210,7 @@ public class OptionsPopupView extends ArrowPopup
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.putExtra(EXTRA_WALLPAPER_OFFSET,
|
||||
launcher.getWorkspace().getWallpaperOffsetForCenterPage());
|
||||
if (!FeatureFlags.STYLE_WALLPAPER.get()) {
|
||||
if (!existsStyleWallpapers(launcher)) {
|
||||
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
|
||||
}
|
||||
String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.view.MotionEvent;
|
||||
@@ -31,13 +32,16 @@ import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.BaseRecyclerView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.graphics.FastScrollThumbDrawable;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The track and scrollbar that shows when you scroll the list.
|
||||
@@ -65,6 +69,9 @@ public class RecyclerViewFastScroller extends View {
|
||||
private final static int SCROLL_BAR_VIS_DURATION = 150;
|
||||
private static final float FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR = 0.75f;
|
||||
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
|
||||
private final int mMinWidth;
|
||||
private final int mMaxWidth;
|
||||
private final int mThumbPadding;
|
||||
@@ -81,6 +88,8 @@ public class RecyclerViewFastScroller extends View {
|
||||
|
||||
private final Paint mThumbPaint;
|
||||
protected final int mThumbHeight;
|
||||
private final RectF mThumbBounds = new RectF();
|
||||
private final Point mThumbDrawOffset = new Point();
|
||||
|
||||
private final Paint mTrackPaint;
|
||||
|
||||
@@ -292,15 +301,23 @@ public class RecyclerViewFastScroller extends View {
|
||||
}
|
||||
int saveCount = canvas.save();
|
||||
canvas.translate(getWidth() / 2, mRv.getScrollBarTop());
|
||||
mThumbDrawOffset.set(getWidth() / 2, mRv.getScrollBarTop());
|
||||
// Draw the track
|
||||
float halfW = mWidth / 2;
|
||||
canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
|
||||
mWidth, mWidth, mTrackPaint);
|
||||
|
||||
canvas.translate(0, mThumbOffsetY);
|
||||
mThumbDrawOffset.y += mThumbOffsetY;
|
||||
halfW += mThumbPadding;
|
||||
float r = getScrollThumbRadius();
|
||||
canvas.drawRoundRect(-halfW, 0, halfW, mThumbHeight, r, r, mThumbPaint);
|
||||
mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
|
||||
canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
|
||||
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
|
||||
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
|
||||
}
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,11 +162,16 @@ abstract class BaseWidgetSheet extends AbstractSlideInView
|
||||
|
||||
@Override
|
||||
public final void logActionCommand(int command) {
|
||||
Target target = newContainerTarget(ContainerType.WIDGETS);
|
||||
Target target = newContainerTarget(getLogContainerType());
|
||||
target.cardinality = getElementsRowCount();
|
||||
mLauncher.getUserEventDispatcher().logActionCommand(command, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.WIDGETS;
|
||||
}
|
||||
|
||||
protected abstract int getElementsRowCount();
|
||||
|
||||
protected SystemUiController getSystemUiController() {
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.android.launcher3.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.IntProperty;
|
||||
import android.util.Pair;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -27,6 +30,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
@@ -43,6 +48,20 @@ import java.util.List;
|
||||
*/
|
||||
public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
|
||||
|
||||
private static final IntProperty<View> PADDING_BOTTOM =
|
||||
new IntProperty<View>("paddingBottom") {
|
||||
@Override
|
||||
public void setValue(View view, int paddingBottom) {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
|
||||
view.getPaddingRight(), paddingBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(View view) {
|
||||
return view.getPaddingBottom();
|
||||
}
|
||||
};
|
||||
|
||||
private static final int DEFAULT_CLOSE_DURATION = 200;
|
||||
private ItemInfo mOriginalItemInfo;
|
||||
private Rect mInsets;
|
||||
@@ -158,8 +177,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
|
||||
int rightInset = insets.right - mInsets.right;
|
||||
int bottomInset = insets.bottom - mInsets.bottom;
|
||||
mInsets.set(insets);
|
||||
setPadding(getPaddingLeft() + leftInset, getPaddingTop(),
|
||||
getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
|
||||
setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,4 +190,10 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
|
||||
return Pair.create(findViewById(R.id.title), getContext().getString(
|
||||
mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Animator createHintCloseAnim(float distanceToMove) {
|
||||
return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.android.launcher3.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
@@ -27,6 +29,9 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
@@ -35,8 +40,6 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
import com.android.launcher3.views.TopRoundedCornerView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Popup for showing the full list of available widgets
|
||||
*/
|
||||
@@ -235,4 +238,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
protected int getElementsRowCount() {
|
||||
return mAdapter.getItemCount();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Animator createHintCloseAnim(float distanceToMove) {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove));
|
||||
anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f));
|
||||
return anim;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,5 +97,13 @@
|
||||
<category android:name="android.intent.category.LAUNCHER_APP" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
|
||||
android:label="LauncherTestApp">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
@@ -63,6 +64,7 @@ public class BaseTestingActivity extends Activity implements View.OnClickListene
|
||||
mView = new LinearLayout(this);
|
||||
mView.setPadding(mMargin, mMargin, mMargin, mMargin);
|
||||
mView.setOrientation(LinearLayout.VERTICAL);
|
||||
mView.setBackgroundColor(Color.BLUE);
|
||||
setContentView(mView);
|
||||
|
||||
registerReceiver(mCommandReceiver, new IntentFilter(mAction + SUFFIX_COMMAND));
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.testcomponent;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
import static android.content.pm.PackageManager.DONT_KILL_APP;
|
||||
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
@@ -28,6 +29,13 @@ import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
@@ -104,4 +112,19 @@ public class TestCommandReceiver extends ContentProvider {
|
||||
Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands");
|
||||
return inst.getTargetContext().getContentResolver().call(uri, command, arg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
String path = Base64.encodeToString(uri.getPath().getBytes(),
|
||||
Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP);
|
||||
File file = new File(getContext().getCacheDir(), path);
|
||||
if (!file.exists()) {
|
||||
// Create an empty file so that we can pass its descriptor
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
|
||||
return ParcelFileDescriptor.open(file, MODE_READ_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,10 +102,6 @@ public abstract class AbstractLauncherUiTest {
|
||||
}
|
||||
if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
|
||||
mLauncher = new LauncherInstrumentation(instrumentation);
|
||||
try {
|
||||
mDevice.executeShellCommand("settings delete secure assistant");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (C) 2019 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.ui;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
|
||||
|
||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.testcomponent.TestCommandReceiver;
|
||||
import com.android.launcher3.util.LauncherLayoutBuilder;
|
||||
import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.UiSelector;
|
||||
|
||||
@MediumTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
|
||||
|
||||
@Rule
|
||||
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
|
||||
|
||||
private static final String SETTINGS_APP = "com.android.settings";
|
||||
|
||||
private Context mContext;
|
||||
private String mAuthority;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mContext = InstrumentationRegistry.getContext();
|
||||
|
||||
PackageManager pm = mTargetContext.getPackageManager();
|
||||
ProviderInfo pi = pm.getProviderInfo(new ComponentName(mContext,
|
||||
TestCommandReceiver.class), 0);
|
||||
mAuthority = pi.authority;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
|
||||
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
|
||||
|
||||
// Launch the home activity
|
||||
mActivityMonitor.startLauncher();
|
||||
waitForModelLoaded();
|
||||
|
||||
// Verify widget present
|
||||
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
|
||||
.description(getSettingsApp().getLabel().toString());
|
||||
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomProfileLoaded_with_widget() throws Exception {
|
||||
// A non-restored widget with no config screen gets restored automatically.
|
||||
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
|
||||
|
||||
writeLayout(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
|
||||
.putWidget(info.getComponent().getPackageName(),
|
||||
info.getComponent().getClassName(), 2, 2));
|
||||
|
||||
// Launch the home activity
|
||||
mActivityMonitor.startLauncher();
|
||||
waitForModelLoaded();
|
||||
|
||||
// Verify widget present
|
||||
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
|
||||
.className(LauncherAppWidgetHostView.class).description(info.label);
|
||||
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomProfileLoaded_with_folder() throws Exception {
|
||||
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
|
||||
.addApp(SETTINGS_APP, SETTINGS_APP)
|
||||
.addApp(SETTINGS_APP, SETTINGS_APP)
|
||||
.addApp(SETTINGS_APP, SETTINGS_APP)
|
||||
.build());
|
||||
|
||||
// Launch the home activity
|
||||
mActivityMonitor.startLauncher();
|
||||
waitForModelLoaded();
|
||||
|
||||
// Verify widget present
|
||||
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
|
||||
.descriptionContains(mTargetContext.getString(android.R.string.copy));
|
||||
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() throws Exception {
|
||||
mDevice.executeShellCommand("settings delete secure launcher3.layout.provider");
|
||||
}
|
||||
|
||||
private void writeLayout(LauncherLayoutBuilder builder) throws Exception {
|
||||
mDevice.executeShellCommand("settings put secure launcher3.layout.provider " + mAuthority);
|
||||
ParcelFileDescriptor pfd = mTargetContext.getContentResolver().openFileDescriptor(
|
||||
Uri.parse("content://" + mAuthority + "/launcher_layout"), "w");
|
||||
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(new AutoCloseOutputStream(pfd))) {
|
||||
builder.build(writer);
|
||||
}
|
||||
clearLauncherData();
|
||||
}
|
||||
}
|
||||
@@ -330,9 +330,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
public void testDragAppIcon() throws Throwable {
|
||||
try {
|
||||
TestProtocol.sDebugTracing = true;
|
||||
LauncherActivityInfo settingsApp = getSettingsApp();
|
||||
|
||||
final String appName = settingsApp.getLabel().toString();
|
||||
final String appName = "LauncherTestApp";
|
||||
// 1. Open all apps and wait for load complete.
|
||||
// 2. Drag icon to homescreen.
|
||||
// 3. Verify that the icon works on homescreen.
|
||||
@@ -341,7 +339,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
getAppIcon(appName).
|
||||
dragToWorkspace().
|
||||
getWorkspaceAppIcon(appName).
|
||||
launch(settingsApp.getComponentName().getPackageName());
|
||||
launch(getInstrumentation().getContext().getPackageName());
|
||||
} finally {
|
||||
TestProtocol.sDebugTracing = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Copyright (C) 2019 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.util;
|
||||
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class to build xml for Launcher Layout
|
||||
*/
|
||||
public class LauncherLayoutBuilder {
|
||||
|
||||
// Object Tags
|
||||
private static final String TAG_WORKSPACE = "workspace";
|
||||
private static final String TAG_AUTO_INSTALL = "autoinstall";
|
||||
private static final String TAG_FOLDER = "folder";
|
||||
private static final String TAG_APPWIDGET = "appwidget";
|
||||
private static final String TAG_EXTRA = "extra";
|
||||
|
||||
private static final String ATTR_CONTAINER = "container";
|
||||
private static final String ATTR_RANK = "rank";
|
||||
|
||||
private static final String ATTR_PACKAGE_NAME = "packageName";
|
||||
private static final String ATTR_CLASS_NAME = "className";
|
||||
private static final String ATTR_TITLE = "title";
|
||||
private static final String ATTR_SCREEN = "screen";
|
||||
|
||||
// x and y can be specified as negative integers, in which case -1 represents the
|
||||
// last row / column, -2 represents the second last, and so on.
|
||||
private static final String ATTR_X = "x";
|
||||
private static final String ATTR_Y = "y";
|
||||
private static final String ATTR_SPAN_X = "spanX";
|
||||
private static final String ATTR_SPAN_Y = "spanY";
|
||||
|
||||
private static final String ATTR_CHILDREN = "children";
|
||||
|
||||
|
||||
// Style attrs -- "Extra"
|
||||
private static final String ATTR_KEY = "key";
|
||||
private static final String ATTR_VALUE = "value";
|
||||
|
||||
private static final String CONTAINER_DESKTOP = "desktop";
|
||||
private static final String CONTAINER_HOTSEAT = "hotseat";
|
||||
|
||||
private final ArrayList<Pair<String, HashMap<String, Object>>> mNodes = new ArrayList<>();
|
||||
|
||||
public Location atHotseat(int rank) {
|
||||
Location l = new Location();
|
||||
l.items.put(ATTR_CONTAINER, CONTAINER_HOTSEAT);
|
||||
l.items.put(ATTR_RANK, Integer.toString(rank));
|
||||
return l;
|
||||
}
|
||||
|
||||
public Location atWorkspace(int x, int y, int screen) {
|
||||
Location l = new Location();
|
||||
l.items.put(ATTR_CONTAINER, CONTAINER_DESKTOP);
|
||||
l.items.put(ATTR_X, Integer.toString(x));
|
||||
l.items.put(ATTR_Y, Integer.toString(y));
|
||||
l.items.put(ATTR_SCREEN, Integer.toString(screen));
|
||||
return l;
|
||||
}
|
||||
|
||||
public String build() throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
build(writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public void build(Writer writer) throws IOException {
|
||||
XmlSerializer serializer = Xml.newSerializer();
|
||||
serializer.setOutput(writer);
|
||||
|
||||
serializer.startDocument("UTF-8", true);
|
||||
serializer.startTag(null, TAG_WORKSPACE);
|
||||
writeNodes(serializer, mNodes);
|
||||
serializer.endTag(null, TAG_WORKSPACE);
|
||||
serializer.endDocument();
|
||||
serializer.flush();
|
||||
}
|
||||
|
||||
private static void writeNodes(XmlSerializer serializer,
|
||||
ArrayList<Pair<String, HashMap<String, Object>>> nodes) throws IOException {
|
||||
for (Pair<String, HashMap<String, Object>> node : nodes) {
|
||||
ArrayList<Pair<String, HashMap<String, Object>>> children = null;
|
||||
|
||||
serializer.startTag(null, node.first);
|
||||
for (Map.Entry<String, Object> attr : node.second.entrySet()) {
|
||||
if (ATTR_CHILDREN.equals(attr.getKey())) {
|
||||
children = (ArrayList<Pair<String, HashMap<String, Object>>>) attr.getValue();
|
||||
} else {
|
||||
serializer.attribute(null, attr.getKey(), (String) attr.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
writeNodes(serializer, children);
|
||||
}
|
||||
serializer.endTag(null, node.first);
|
||||
}
|
||||
}
|
||||
|
||||
public class Location {
|
||||
|
||||
final HashMap<String, Object> items = new HashMap<>();
|
||||
|
||||
public LauncherLayoutBuilder putApp(String packageName, String className) {
|
||||
items.put(ATTR_PACKAGE_NAME, packageName);
|
||||
items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
|
||||
mNodes.add(Pair.create(TAG_AUTO_INSTALL, items));
|
||||
return LauncherLayoutBuilder.this;
|
||||
}
|
||||
|
||||
public LauncherLayoutBuilder putWidget(String packageName, String className,
|
||||
int spanX, int spanY) {
|
||||
items.put(ATTR_PACKAGE_NAME, packageName);
|
||||
items.put(ATTR_CLASS_NAME, className);
|
||||
items.put(ATTR_SPAN_X, Integer.toString(spanX));
|
||||
items.put(ATTR_SPAN_Y, Integer.toString(spanY));
|
||||
mNodes.add(Pair.create(TAG_APPWIDGET, items));
|
||||
return LauncherLayoutBuilder.this;
|
||||
}
|
||||
|
||||
public FolderBuilder putFolder(int titleResId) {
|
||||
FolderBuilder folderBuilder = new FolderBuilder();
|
||||
items.put(ATTR_TITLE, Integer.toString(titleResId));
|
||||
items.put(ATTR_CHILDREN, folderBuilder.mChildren);
|
||||
mNodes.add(Pair.create(TAG_FOLDER, items));
|
||||
return folderBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
public class FolderBuilder {
|
||||
|
||||
final ArrayList<Pair<String, HashMap<String, Object>>> mChildren = new ArrayList<>();
|
||||
|
||||
public FolderBuilder addApp(String packageName, String className) {
|
||||
HashMap<String, Object> items = new HashMap<>();
|
||||
items.put(ATTR_PACKAGE_NAME, packageName);
|
||||
items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
|
||||
mChildren.add(Pair.create(TAG_AUTO_INSTALL, items));
|
||||
return this;
|
||||
}
|
||||
|
||||
public LauncherLayoutBuilder build() {
|
||||
return LauncherLayoutBuilder.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import androidx.test.uiautomator.Until;
|
||||
* Ancestor for AppIcon and AppMenuItem.
|
||||
*/
|
||||
class Launchable {
|
||||
private static final int DRAG_SPEED = 500;
|
||||
protected final LauncherInstrumentation mLauncher;
|
||||
|
||||
protected final UiObject2 mObject;
|
||||
@@ -77,8 +76,7 @@ class Launchable {
|
||||
Workspace.dragIconToWorkspace(
|
||||
mLauncher,
|
||||
this,
|
||||
new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
|
||||
DRAG_SPEED);
|
||||
new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2));
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"dragged launchable to workspace")) {
|
||||
return new Workspace(mLauncher);
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.launcher3.tapl;
|
||||
|
||||
import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
|
||||
import static com.android.launcher3.TestProtocol.NORMAL_STATE_ORDINAL;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.UiAutomation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -172,11 +176,11 @@ public final class LauncherInstrumentation {
|
||||
// Workaround, use constructed context because both the instrumentation context and the
|
||||
// app context are not constructed with resources that take overlays into account
|
||||
final Context ctx = baseContext.createPackageContext("android", 0);
|
||||
if (QuickStepContract.isGesturalMode(ctx)) {
|
||||
if (isGesturalMode(ctx)) {
|
||||
return NavigationModel.ZERO_BUTTON;
|
||||
} else if (QuickStepContract.isSwipeUpMode(ctx)) {
|
||||
} else if (isSwipeUpMode(ctx)) {
|
||||
return NavigationModel.TWO_BUTTON;
|
||||
} else if (QuickStepContract.isLegacyMode(ctx)) {
|
||||
} else if (isLegacyMode(ctx)) {
|
||||
return NavigationModel.THREE_BUTTON;
|
||||
} else {
|
||||
fail("Can't detect navigation mode");
|
||||
@@ -343,18 +347,33 @@ public final class LauncherInstrumentation {
|
||||
log(action = "0-button: already in workspace");
|
||||
} else if (hasLauncherObject(OVERVIEW_RES_ID)) {
|
||||
log(action = "0-button: from overview");
|
||||
mDevice.pressHome();
|
||||
final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
|
||||
|
||||
swipe(
|
||||
navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
|
||||
navBar.getVisibleBounds().centerX(), 0,
|
||||
NORMAL_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
|
||||
} else if (hasLauncherObject(WIDGETS_RES_ID)) {
|
||||
log(action = "0-button: from widgets");
|
||||
mDevice.pressHome();
|
||||
} else if (hasLauncherObject(APPS_RES_ID)) {
|
||||
log(action = "0-button: from all apps");
|
||||
mDevice.pressHome();
|
||||
final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
|
||||
|
||||
swipe(
|
||||
navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
|
||||
navBar.getVisibleBounds().centerX(), 0,
|
||||
NORMAL_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
|
||||
} else {
|
||||
log(action = "0-button: from another app");
|
||||
assertTrue("Launcher is visible, don't know how to go home",
|
||||
!mDevice.hasObject(By.pkg(getLauncherPackageName())));
|
||||
mDevice.pressHome();
|
||||
final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
|
||||
|
||||
swipe(
|
||||
navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
|
||||
navBar.getVisibleBounds().centerX(), 0,
|
||||
BACKGROUND_APP_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
|
||||
}
|
||||
} else {
|
||||
log(action = "clicking home button");
|
||||
@@ -607,6 +626,46 @@ public final class LauncherInstrumentation {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGesturalMode(Context context) {
|
||||
return QuickStepContract.isGesturalMode(getCurrentInteractionMode(context));
|
||||
}
|
||||
|
||||
public static boolean isSwipeUpMode(Context context) {
|
||||
return QuickStepContract.isSwipeUpMode(getCurrentInteractionMode(context));
|
||||
}
|
||||
|
||||
public static boolean isLegacyMode(Context context) {
|
||||
return QuickStepContract.isLegacyMode(getCurrentInteractionMode(context));
|
||||
}
|
||||
|
||||
private static int getCurrentInteractionMode(Context context) {
|
||||
return getSystemIntegerRes(context, "config_navBarInteractionMode");
|
||||
}
|
||||
|
||||
private static int getSystemIntegerRes(Context context, String resName) {
|
||||
Resources res = context.getResources();
|
||||
int resId = res.getIdentifier(resName, "integer", "android");
|
||||
|
||||
if (resId != 0) {
|
||||
return res.getInteger(resId);
|
||||
} else {
|
||||
Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getSystemDimensionResId(Context context, String resName) {
|
||||
Resources res = context.getResources();
|
||||
int resId = res.getIdentifier(resName, "dimen", "android");
|
||||
|
||||
if (resId != 0) {
|
||||
return resId;
|
||||
} else {
|
||||
Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep(int duration) {
|
||||
try {
|
||||
Thread.sleep(duration);
|
||||
@@ -616,8 +675,10 @@ public final class LauncherInstrumentation {
|
||||
|
||||
int getEdgeSensitivityWidth() {
|
||||
try {
|
||||
return QuickStepContract.getEdgeSensitivityWidth(
|
||||
mInstrumentation.getTargetContext().createPackageContext("android", 0)) + 1;
|
||||
final Context context = mInstrumentation.getTargetContext().createPackageContext(
|
||||
"android", 0);
|
||||
return context.getResources().getDimensionPixelSize(
|
||||
getSystemDimensionResId(context, "config_backGestureInset")) + 1;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
fail("Can't get edge sensitivity: " + e);
|
||||
return 0;
|
||||
|
||||
@@ -21,7 +21,9 @@ import static com.android.launcher3.TestProtocol.ALL_APPS_STATE_ORDINAL;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.os.SystemClock;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -35,8 +37,8 @@ import com.android.launcher3.TestProtocol;
|
||||
*/
|
||||
public final class Workspace extends Home {
|
||||
private static final float FLING_SPEED = 3500.0F;
|
||||
private static final int DRAG_DURACTION = 2000;
|
||||
private final UiObject2 mHotseat;
|
||||
private final int ICON_DRAG_SPEED = LauncherInstrumentation.needSlowGestures() ? 100 : 570;
|
||||
|
||||
Workspace(LauncherInstrumentation launcher) {
|
||||
super(launcher);
|
||||
@@ -116,8 +118,7 @@ public final class Workspace extends Home {
|
||||
mLauncher,
|
||||
getHotseatAppIcon("Chrome"),
|
||||
new Point(mLauncher.getDevice().getDisplayWidth(),
|
||||
workspace.getVisibleBounds().centerY()),
|
||||
(int) (ICON_DRAG_SPEED * mLauncher.getDisplayDensity()));
|
||||
workspace.getVisibleBounds().centerY()));
|
||||
verifyActiveContainer();
|
||||
}
|
||||
assertTrue("Home screen workspace didn't become scrollable",
|
||||
@@ -134,10 +135,16 @@ public final class Workspace extends Home {
|
||||
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
|
||||
}
|
||||
|
||||
static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
|
||||
Point dest, int icon_drag_speed) {
|
||||
static void dragIconToWorkspace(
|
||||
LauncherInstrumentation launcher, Launchable launchable, Point dest) {
|
||||
LauncherInstrumentation.log("dragIconToWorkspace: begin");
|
||||
launchable.getObject().drag(dest, icon_drag_speed);
|
||||
final Point launchableCenter = launchable.getObject().getVisibleCenter();
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, launchableCenter);
|
||||
launcher.waitForLauncherObject("deep_shortcuts_container");
|
||||
launcher.movePointer(downTime, DRAG_DURACTION, launchableCenter, dest);
|
||||
launcher.sendPointer(
|
||||
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
|
||||
LauncherInstrumentation.log("dragIconToWorkspace: end");
|
||||
launcher.waitUntilGone("drop_target_bar");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user