Merging ub-launcher3-qt-dev, build 5528135
am: 4c8e5dd275
Change-Id: Ic9ece52afbf3b61453a17bc4f85f79093622852c
This commit is contained in:
+1
-1
@@ -298,7 +298,7 @@ LOCAL_PROGUARD_ENABLED := full
|
||||
LOCAL_PACKAGE_NAME := Launcher3GoIconRecents
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_PRODUCT_MODULE := true
|
||||
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3QuickStep Launcher3QuickStepGo
|
||||
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3Go Launcher3QuickStep Launcher3QuickStepGo
|
||||
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
|
||||
|
||||
LOCAL_FULL_LIBS_MANIFEST_FILES := \
|
||||
|
||||
@@ -14,22 +14,20 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.quickstep.views.ClearAllItemView
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/clear_all_item_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="@dimen/clear_all_item_view_height">
|
||||
<Button
|
||||
android:id="@+id/clear_all_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="16dp"
|
||||
android:layout_width="@dimen/clear_all_button_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:background="@drawable/clear_all_button"
|
||||
android:gravity="center"
|
||||
android:text="@string/recents_clear_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/clear_all_button_text"
|
||||
android:textSize="14sp"/>
|
||||
</com.android.quickstep.views.ClearAllItemView>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:clipChildren="false">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recent_task_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="@dimen/recents_list_width"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"/>
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scrollbars="none"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"/>
|
||||
<TextView
|
||||
android:id="@+id/recent_task_empty_view"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -17,14 +17,13 @@
|
||||
<com.android.quickstep.views.TaskItemView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="@dimen/task_item_height"
|
||||
android:orientation="horizontal">
|
||||
<com.android.quickstep.views.TaskThumbnailIconView
|
||||
android:id="@+id/task_icon_and_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginTop="16dp">
|
||||
android:layout_marginHorizontal="@dimen/task_thumbnail_icon_horiz_margin">
|
||||
<ImageView
|
||||
android:id="@+id/task_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
@@ -39,7 +38,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
<resources>
|
||||
<dimen name="recents_list_width">480dp</dimen>
|
||||
|
||||
<dimen name="task_item_height">90dp</dimen>
|
||||
<dimen name="task_item_top_margin">16dp</dimen>
|
||||
<dimen name="task_thumbnail_icon_horiz_margin">20dp</dimen>
|
||||
|
||||
<dimen name="task_thumbnail_corner_radius">4dp</dimen>
|
||||
|
||||
<dimen name="clear_all_item_view_height">48dp</dimen>
|
||||
<dimen name="clear_all_item_view_top_margin">28dp</dimen>
|
||||
<dimen name="clear_all_item_view_bottom_margin">28dp</dimen>
|
||||
<dimen name="clear_all_button_width">140dp</dimen>
|
||||
</resources>
|
||||
@@ -15,5 +15,16 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<dimen name="recents_list_width">320dp</dimen>
|
||||
|
||||
<dimen name="task_item_height">60dp</dimen>
|
||||
<dimen name="task_item_top_margin">16dp</dimen>
|
||||
<dimen name="task_thumbnail_icon_horiz_margin">16dp</dimen>
|
||||
|
||||
<dimen name="task_thumbnail_corner_radius">3dp</dimen>
|
||||
|
||||
<dimen name="clear_all_item_view_height">36dp</dimen>
|
||||
<dimen name="clear_all_item_view_top_margin">20dp</dimen>
|
||||
<dimen name="clear_all_item_view_bottom_margin">20dp</dimen>
|
||||
<dimen name="clear_all_button_width">106dp</dimen>
|
||||
</resources>
|
||||
@@ -52,11 +52,18 @@ public class OverviewState extends LauncherState {
|
||||
public void onStateEnabled(Launcher launcher) {
|
||||
IconRecentsView recentsView = launcher.getOverviewPanel();
|
||||
recentsView.onBeginTransitionToOverview();
|
||||
recentsView.setShowStatusBarForegroundScrim(true);
|
||||
// Request orientation be set to unspecified, letting the system decide the best
|
||||
// orientation.
|
||||
launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateDisabled(Launcher launcher) {
|
||||
IconRecentsView recentsView = launcher.getOverviewPanel();
|
||||
recentsView.setShowStatusBarForegroundScrim(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
||||
return new PageAlphaProvider(DEACCEL_2) {
|
||||
|
||||
@@ -37,6 +37,7 @@ public final class RecentsActivity extends BaseRecentsActivity {
|
||||
mRecentsRootView = findViewById(R.id.drag_layer);
|
||||
mIconRecentsView = findViewById(R.id.overview_panel);
|
||||
mIconRecentsView.setRecentsToActivityHelper(new FallbackRecentsToActivityHelper(this));
|
||||
mIconRecentsView.setShowStatusBarForegroundScrim(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -80,7 +80,8 @@ public final class TaskListLoader {
|
||||
return;
|
||||
}
|
||||
// TODO: Look into error checking / more robust handling for when things go wrong.
|
||||
mTaskListChangeId = mRecentsModel.getTasks(tasks -> {
|
||||
mTaskListChangeId = mRecentsModel.getTasks(loadedTasks -> {
|
||||
ArrayList<Task> tasks = new ArrayList<>(loadedTasks);
|
||||
// Reverse tasks to put most recent at the bottom of the view
|
||||
Collections.reverse(tasks);
|
||||
// Load task content
|
||||
|
||||
@@ -19,21 +19,25 @@ import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
|
||||
|
||||
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_CLEAR_ALL;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Callback for swipe input on {@link TaskHolder} views in the recents view.
|
||||
*/
|
||||
public final class TaskSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
private final TaskActionController mTaskActionController;
|
||||
private final Consumer<TaskHolder> mOnTaskSwipeCallback;
|
||||
|
||||
public TaskSwipeCallback(TaskActionController taskActionController) {
|
||||
public TaskSwipeCallback(Consumer<TaskHolder> onTaskSwipeCallback) {
|
||||
super(0 /* dragDirs */, RIGHT);
|
||||
mTaskActionController = taskActionController;
|
||||
mOnTaskSwipeCallback = onTaskSwipeCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,10 +49,22 @@ public final class TaskSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
@Override
|
||||
public void onSwiped(ViewHolder viewHolder, int direction) {
|
||||
if (direction == RIGHT) {
|
||||
mTaskActionController.removeTask((TaskHolder) viewHolder);
|
||||
mOnTaskSwipeCallback.accept((TaskHolder) viewHolder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
|
||||
@NonNull ViewHolder viewHolder, float dX, float dY, int actionState,
|
||||
boolean isCurrentlyActive) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
float alpha = 1.0f - dX / (float) viewHolder.itemView.getWidth();
|
||||
viewHolder.itemView.setAlpha(alpha);
|
||||
}
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY,
|
||||
actionState, isCurrentlyActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirs(@NonNull RecyclerView recyclerView,
|
||||
@NonNull ViewHolder viewHolder) {
|
||||
|
||||
@@ -57,6 +57,7 @@ public final class ThumbnailDrawable extends Drawable {
|
||||
mCornerRadius = (int) res.getDimension(R.dimen.task_thumbnail_corner_radius);
|
||||
mShader = new BitmapShader(mThumbnailData.thumbnail, CLAMP, CLAMP);
|
||||
mPaint.setShader(mShader);
|
||||
mPaint.setAntiAlias(true);
|
||||
updateMatrix();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.quickstep.views;
|
||||
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getClearAllItemHeight;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Recycler view item that lays out the clear all button and measures the space it takes based on
|
||||
* the device height.
|
||||
*/
|
||||
public final class ClearAllItemView extends FrameLayout {
|
||||
|
||||
public ClearAllItemView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int buttonHeight = getClearAllItemHeight(getContext());
|
||||
int newHeightSpec = MeasureSpec.makeMeasureSpec(buttonHeight, MeasureSpec.EXACTLY);
|
||||
super.onMeasure(widthMeasureSpec, newHeightSpec);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static androidx.recyclerview.widget.LinearLayoutManager.VERTICAL;
|
||||
|
||||
import static com.android.quickstep.TaskAdapter.CHANGE_EVENT_TYPE_EMPTY_TO_CONTENT;
|
||||
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_CLEAR_ALL;
|
||||
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_TASK;
|
||||
import static com.android.quickstep.TaskAdapter.TASKS_START_POSITION;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -29,6 +31,9 @@ import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
@@ -44,10 +49,13 @@ import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
|
||||
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
|
||||
import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.quickstep.ContentFillItemAnimator;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsToActivityHelper;
|
||||
@@ -67,7 +75,7 @@ import java.util.Optional;
|
||||
* Root view for the icon recents view. Acts as the main interface to the rest of the Launcher code
|
||||
* base.
|
||||
*/
|
||||
public final class IconRecentsView extends FrameLayout {
|
||||
public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
|
||||
public static final FloatProperty<IconRecentsView> CONTENT_ALPHA =
|
||||
new FloatProperty<IconRecentsView>("contentAlpha") {
|
||||
@@ -108,6 +116,8 @@ public final class IconRecentsView extends FrameLayout {
|
||||
private final DefaultItemAnimator mDefaultItemAnimator = new DefaultItemAnimator();
|
||||
private final ContentFillItemAnimator mLoadingContentItemAnimator =
|
||||
new ContentFillItemAnimator();
|
||||
private final BaseActivity mActivity;
|
||||
private final Drawable mStatusBarForegroundScrim;
|
||||
|
||||
private RecentsToActivityHelper mActivityHelper;
|
||||
private RecyclerView mTaskRecyclerView;
|
||||
@@ -117,6 +127,7 @@ public final class IconRecentsView extends FrameLayout {
|
||||
private boolean mTransitionedFromApp;
|
||||
private AnimatorSet mLayoutAnimation;
|
||||
private final ArraySet<View> mLayingOutViews = new ArraySet<>();
|
||||
private Rect mInsets;
|
||||
private final RecentsModel.TaskThumbnailChangeListener listener = (taskId, thumbnailData) -> {
|
||||
ArrayList<TaskItemView> itemViews = getTaskViews();
|
||||
for (int i = 0, size = itemViews.size(); i < size; i++) {
|
||||
@@ -136,8 +147,10 @@ public final class IconRecentsView extends FrameLayout {
|
||||
|
||||
public IconRecentsView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
BaseActivity activity = BaseActivity.fromContext(context);
|
||||
mActivity = BaseActivity.fromContext(context);
|
||||
mContext = context;
|
||||
mStatusBarForegroundScrim =
|
||||
Themes.getAttrDrawable(mContext, R.attr.workspaceStatusBarScrim);
|
||||
mTaskLoader = new TaskListLoader(mContext);
|
||||
mTaskAdapter = new TaskAdapter(mTaskLoader);
|
||||
mTaskAdapter.setOnClearAllClickListener(view -> animateClearAllTasks());
|
||||
@@ -155,7 +168,12 @@ public final class IconRecentsView extends FrameLayout {
|
||||
mTaskRecyclerView.setAdapter(mTaskAdapter);
|
||||
mTaskRecyclerView.setLayoutManager(mTaskLayoutManager);
|
||||
ItemTouchHelper helper = new ItemTouchHelper(
|
||||
new TaskSwipeCallback(mTaskActionController));
|
||||
new TaskSwipeCallback(holder -> {
|
||||
mTaskActionController.removeTask(holder);
|
||||
if (mTaskLoader.getCurrentTaskList().isEmpty()) {
|
||||
mActivityHelper.leaveRecents();
|
||||
}
|
||||
}));
|
||||
helper.attachToRecyclerView(mTaskRecyclerView);
|
||||
mTaskRecyclerView.addOnChildAttachStateChangeListener(
|
||||
new OnChildAttachStateChangeListener() {
|
||||
@@ -174,6 +192,43 @@ public final class IconRecentsView extends FrameLayout {
|
||||
mTaskRecyclerView.setItemAnimator(mDefaultItemAnimator);
|
||||
mLoadingContentItemAnimator.setOnAnimationFinishedRunnable(
|
||||
() -> mTaskRecyclerView.setItemAnimator(new DefaultItemAnimator()));
|
||||
ItemDecoration marginDecorator = new ItemDecoration() {
|
||||
@Override
|
||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
|
||||
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
// TODO: Determine if current margins cause off screen item to be fully off
|
||||
// screen and if so, modify them so that it is partially off screen.
|
||||
int itemType = parent.getChildViewHolder(view).getItemViewType();
|
||||
Resources res = getResources();
|
||||
switch (itemType) {
|
||||
case ITEM_TYPE_CLEAR_ALL:
|
||||
outRect.top = (int) res.getDimension(
|
||||
R.dimen.clear_all_item_view_top_margin);
|
||||
int desiredBottomMargin = (int) res.getDimension(
|
||||
R.dimen.clear_all_item_view_bottom_margin);
|
||||
// Only add bottom margin if insets aren't enough.
|
||||
if (mInsets.bottom < desiredBottomMargin) {
|
||||
outRect.bottom = desiredBottomMargin - mInsets.bottom;
|
||||
}
|
||||
break;
|
||||
case ITEM_TYPE_TASK:
|
||||
int desiredTopMargin = (int) res.getDimension(
|
||||
R.dimen.task_item_top_margin);
|
||||
if (mTaskRecyclerView.getChildAdapterPosition(view) ==
|
||||
state.getItemCount() - 1) {
|
||||
// Only add top margin to top task view if insets aren't enough.
|
||||
if (mInsets.top < desiredTopMargin) {
|
||||
outRect.top = desiredTopMargin - mInsets.bottom;
|
||||
}
|
||||
return;
|
||||
}
|
||||
outRect.top = desiredTopMargin;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
};
|
||||
mTaskRecyclerView.addItemDecoration(marginDecorator);
|
||||
|
||||
mEmptyView = findViewById(R.id.recent_task_empty_view);
|
||||
mContentView = mTaskRecyclerView;
|
||||
@@ -188,7 +243,6 @@ public final class IconRecentsView extends FrameLayout {
|
||||
updateContentViewVisibility();
|
||||
}
|
||||
});
|
||||
// TODO: Move layout param logic into onMeasure
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +349,21 @@ public final class IconRecentsView extends FrameLayout {
|
||||
mTaskActionController.launchTask(taskToLaunch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to show the scrim in between the view and the top insets. This only works
|
||||
* if the view is being insetted in the first place.
|
||||
*
|
||||
* The scrim is added to the activity's root view to prevent animations on this view
|
||||
* affecting the scrim. As a result, it is the activity's responsibility to show/hide this
|
||||
* scrim as appropriate.
|
||||
*
|
||||
* @param showStatusBarForegroundScrim true to show the scrim, false to hide
|
||||
*/
|
||||
public void setShowStatusBarForegroundScrim(boolean showStatusBarForegroundScrim) {
|
||||
boolean shouldShow = mInsets.top != 0 && showStatusBarForegroundScrim;
|
||||
mActivity.getDragLayer().setForeground(shouldShow ? mStatusBarForegroundScrim : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bottom most thumbnail view to animate to.
|
||||
*
|
||||
@@ -395,7 +464,6 @@ public final class IconRecentsView extends FrameLayout {
|
||||
if (mShowingContentView != mEmptyView && taskListSize == 0) {
|
||||
mShowingContentView = mEmptyView;
|
||||
crossfadeViews(mEmptyView, mContentView);
|
||||
mActivityHelper.leaveRecents();
|
||||
}
|
||||
if (mShowingContentView != mContentView && taskListSize > 0) {
|
||||
mShowingContentView = mContentView;
|
||||
@@ -482,4 +550,11 @@ public final class IconRecentsView extends FrameLayout {
|
||||
});
|
||||
mLayoutAnimation.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets = insets;
|
||||
mTaskRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
mTaskRecyclerView.invalidateItemDecorations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getTaskHeight;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
@@ -46,10 +44,12 @@ public final class TaskItemView extends LinearLayout {
|
||||
private final Drawable mDefaultThumbnail;
|
||||
private final TaskLayerDrawable mIconDrawable;
|
||||
private final TaskLayerDrawable mThumbnailDrawable;
|
||||
private View mTaskIconThumbnailView;
|
||||
private TextView mLabelView;
|
||||
private ImageView mIconView;
|
||||
private ImageView mThumbnailView;
|
||||
private float mContentTransitionProgress;
|
||||
private int mDisplayedOrientation;
|
||||
|
||||
/**
|
||||
* Property representing the content transition progress of the view. 1.0f represents that the
|
||||
@@ -81,6 +81,7 @@ public final class TaskItemView extends LinearLayout {
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mLabelView = findViewById(R.id.task_label);
|
||||
mTaskIconThumbnailView = findViewById(R.id.task_icon_and_thumbnail);
|
||||
mThumbnailView = findViewById(R.id.task_thumbnail);
|
||||
mIconView = findViewById(R.id.task_icon);
|
||||
|
||||
@@ -91,13 +92,6 @@ public final class TaskItemView extends LinearLayout {
|
||||
CONTENT_TRANSITION_PROGRESS.setValue(this, 1.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int taskHeight = getTaskHeight(getContext());
|
||||
int newHeightSpec = MeasureSpec.makeMeasureSpec(taskHeight,MeasureSpec.EXACTLY);
|
||||
super.onMeasure(widthMeasureSpec, newHeightSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets task item view to empty, loading UI.
|
||||
*/
|
||||
@@ -185,15 +179,30 @@ public final class TaskItemView extends LinearLayout {
|
||||
return (label != null) ? label : DEFAULT_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
onOrientationChanged(getResources().getConfiguration().orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
onOrientationChanged(newConfig.orientation);
|
||||
}
|
||||
|
||||
private void onOrientationChanged(int newOrientation) {
|
||||
if (mDisplayedOrientation == newOrientation) {
|
||||
return;
|
||||
}
|
||||
mDisplayedOrientation = newOrientation;
|
||||
int layerCount = mThumbnailDrawable.getNumberOfLayers();
|
||||
for (int i = 0; i < layerCount; i++) {
|
||||
Drawable drawable = mThumbnailDrawable.getDrawable(i);
|
||||
if (drawable instanceof ThumbnailDrawable) {
|
||||
((ThumbnailDrawable) drawable).setRequestedOrientation(newConfig.orientation);
|
||||
((ThumbnailDrawable) drawable).setRequestedOrientation(newOrientation);
|
||||
}
|
||||
}
|
||||
mTaskIconThumbnailView.forceLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.quickstep.views;
|
||||
|
||||
import static com.android.quickstep.TaskAdapter.MAX_TASKS_TO_DISPLAY;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
|
||||
/**
|
||||
* Utils to determine dynamically task and view sizes based off the device height and width.
|
||||
*/
|
||||
public final class TaskLayoutUtils {
|
||||
|
||||
private static final float CLEAR_ALL_ITEM_TO_HEIGHT_RATIO = 7.0f / 64;
|
||||
|
||||
private TaskLayoutUtils() {}
|
||||
|
||||
/**
|
||||
* Calculate task height based off the available height in portrait mode such that when the
|
||||
* recents list is full, the total height fills in the available device height perfectly. In
|
||||
* landscape mode, we keep the same task height so that tasks scroll off the top.
|
||||
*
|
||||
* @param context current context
|
||||
* @return task height
|
||||
*/
|
||||
public static int getTaskHeight(Context context) {
|
||||
final int availableHeight =
|
||||
InvariantDeviceProfile.INSTANCE.get(context).portraitProfile.availableHeightPx;
|
||||
final int availableTaskSpace = availableHeight - getClearAllItemHeight(context);
|
||||
return (int) (availableTaskSpace * 1.0f / MAX_TASKS_TO_DISPLAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate clear all item height scaled to available height in portrait mode.
|
||||
*
|
||||
* @param context current context
|
||||
* @return clear all item height
|
||||
*/
|
||||
public static int getClearAllItemHeight(Context context) {
|
||||
final int availableHeight =
|
||||
InvariantDeviceProfile.INSTANCE.get(context).portraitProfile.availableHeightPx;
|
||||
return (int) (CLEAR_ALL_ITEM_TO_HEIGHT_RATIO * availableHeight);
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ final class TaskThumbnailIconView extends ViewGroup {
|
||||
int width = height;
|
||||
setMeasuredDimension(width, height);
|
||||
|
||||
|
||||
int subItemSize = (int) (SUBITEM_FRAME_RATIO * height);
|
||||
if (mThumbnailView.getVisibility() != GONE) {
|
||||
boolean isPortrait =
|
||||
|
||||
@@ -21,4 +21,6 @@
|
||||
<!-- The size of corner radius of the arrow in the arrow toast. -->
|
||||
<dimen name="arrow_toast_corner_radius">2dp</dimen>
|
||||
|
||||
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
||||
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
|
||||
</resources>
|
||||
+10
-37
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.launcher3.appprediction.PredictionUiStateManager.KEY_APP_SUGGESTION;
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.prediction.AppPredictionContext;
|
||||
@@ -26,8 +26,6 @@ import android.app.prediction.AppTargetEvent;
|
||||
import android.app.prediction.AppTargetId;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
@@ -35,12 +33,10 @@ import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
@@ -48,8 +44,7 @@ import androidx.annotation.WorkerThread;
|
||||
* Subclass of app tracker which publishes the data to the prediction engine and gets back results.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class PredictionAppTracker extends AppLaunchTracker
|
||||
implements OnSharedPreferenceChangeListener {
|
||||
public class PredictionAppTracker extends AppLaunchTracker {
|
||||
|
||||
private static final String TAG = "PredictionAppTracker";
|
||||
private static final boolean DBG = false;
|
||||
@@ -62,8 +57,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
private final Context mContext;
|
||||
private final Handler mMessageHandler;
|
||||
|
||||
private boolean mEnabled;
|
||||
|
||||
// Accessed only on worker thread
|
||||
private AppPredictor mHomeAppPredictor;
|
||||
private AppPredictor mRecentsOverviewPredictor;
|
||||
@@ -71,24 +64,16 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
public PredictionAppTracker(Context context) {
|
||||
mContext = context;
|
||||
mMessageHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleMessage);
|
||||
|
||||
SharedPreferences prefs = Utilities.getPrefs(context);
|
||||
setEnabled(prefs.getBoolean(KEY_APP_SUGGESTION, true));
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged);
|
||||
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
|
||||
// Reinitialize everything
|
||||
setEnabled(mEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
if (KEY_APP_SUGGESTION.equals(key)) {
|
||||
setEnabled(prefs.getBoolean(KEY_APP_SUGGESTION, true));
|
||||
if ((changeFlags & CHANGE_FLAG_GRID) != 0) {
|
||||
// Reinitialize everything
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,13 +122,13 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
return true;
|
||||
}
|
||||
case MSG_LAUNCH: {
|
||||
if (mEnabled && mHomeAppPredictor != null) {
|
||||
if (mHomeAppPredictor != null) {
|
||||
mHomeAppPredictor.notifyAppTargetEvent((AppTargetEvent) msg.obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MSG_PREDICT: {
|
||||
if (mEnabled && mHomeAppPredictor != null) {
|
||||
if (mHomeAppPredictor != null) {
|
||||
String client = (String) msg.obj;
|
||||
if (Client.HOME.id.equals(client)) {
|
||||
mHomeAppPredictor.requestPredictionUpdate();
|
||||
@@ -168,18 +153,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
mEnabled = isEnabled;
|
||||
if (isEnabled) {
|
||||
mMessageHandler.removeMessages(MSG_DESTROY);
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
} else {
|
||||
mMessageHandler.removeMessages(MSG_INIT);
|
||||
mMessageHandler.sendEmptyMessage(MSG_DESTROY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
|
||||
|
||||
+30
-17
@@ -24,8 +24,7 @@ import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Handler;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
@@ -61,9 +60,10 @@ import java.util.List;
|
||||
* that client id.
|
||||
*/
|
||||
public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInfoUpdateReceiver,
|
||||
OnSharedPreferenceChangeListener, OnIDPChangeListener, OnUpdateListener {
|
||||
OnIDPChangeListener, OnUpdateListener {
|
||||
|
||||
public static final String KEY_APP_SUGGESTION = "pref_show_predictions";
|
||||
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
|
||||
private static final long INITIAL_CALLBACK_WAIT_TIMEOUT_MS = 5000;
|
||||
|
||||
// TODO (b/129421797): Update the client constants
|
||||
public enum Client {
|
||||
@@ -81,7 +81,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
new MainThreadInitializedObject<>(PredictionUiStateManager::new);
|
||||
|
||||
private final Context mContext;
|
||||
private final SharedPreferences mMainPrefs;
|
||||
|
||||
private final DynamicItemCache mDynamicItemCache;
|
||||
private final List[] mPredictionServicePredictions;
|
||||
@@ -94,9 +93,10 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
private PredictionState mPendingState;
|
||||
private PredictionState mCurrentState;
|
||||
|
||||
private boolean mGettingValidPredictionResults;
|
||||
|
||||
private PredictionUiStateManager(Context context) {
|
||||
mContext = context;
|
||||
mMainPrefs = Utilities.getPrefs(context);
|
||||
|
||||
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
|
||||
|
||||
@@ -110,8 +110,14 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
for (int i = 0; i < mPredictionServicePredictions.length; i++) {
|
||||
mPredictionServicePredictions[i] = Collections.emptyList();
|
||||
}
|
||||
// Listens for enable/disable signal, and predictions if using AiAi is disabled.
|
||||
mMainPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
|
||||
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
|
||||
if (mGettingValidPredictionResults) {
|
||||
new Handler().postDelayed(
|
||||
this::updatePredictionStateAfterCallback, INITIAL_CALLBACK_WAIT_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
// Call this last
|
||||
mCurrentState = parseLastState();
|
||||
}
|
||||
@@ -177,13 +183,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
if (KEY_APP_SUGGESTION.equals(key)) {
|
||||
dispatchOnChange(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyState(PredictionState state) {
|
||||
boolean wasEnabled = mCurrentState.isEnabled;
|
||||
mCurrentState = state;
|
||||
@@ -198,10 +197,24 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePredictionStateAfterCallback() {
|
||||
boolean validResults = false;
|
||||
for (List l : mPredictionServicePredictions) {
|
||||
validResults |= l != null && !l.isEmpty();
|
||||
}
|
||||
if (validResults != mGettingValidPredictionResults) {
|
||||
mGettingValidPredictionResults = validResults;
|
||||
Utilities.getDevicePrefs(mContext).edit()
|
||||
.putBoolean(LAST_PREDICTION_ENABLED_STATE, true)
|
||||
.apply();
|
||||
}
|
||||
dispatchOnChange(true);
|
||||
}
|
||||
|
||||
public AppPredictor.Callback appPredictorCallback(Client client) {
|
||||
return targets -> {
|
||||
mPredictionServicePredictions[client.ordinal()] = targets;
|
||||
dispatchOnChange(true);
|
||||
updatePredictionStateAfterCallback();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -217,7 +230,7 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
|
||||
|
||||
private PredictionState parseLastState() {
|
||||
PredictionState state = new PredictionState();
|
||||
state.isEnabled = mMainPrefs.getBoolean(KEY_APP_SUGGESTION, true);
|
||||
state.isEnabled = mGettingValidPredictionResults;
|
||||
if (!state.isEnabled) {
|
||||
state.apps = Collections.EMPTY_LIST;
|
||||
return state;
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.quickstep;
|
||||
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
/**
|
||||
* Touch consumer for two finger swipe actions for accessibility actions
|
||||
*/
|
||||
public class AccessibilityInputConsumer extends DelegateInputConsumer {
|
||||
|
||||
private static final String TAG = "A11yInputConsumer";
|
||||
|
||||
private final ISystemUiProxy mSystemUiProxy;
|
||||
private final VelocityTracker mVelocityTracker;
|
||||
private final MotionPauseDetector mMotionPauseDetector;
|
||||
private final boolean mAllowLongClick;
|
||||
|
||||
private final float mMinGestureDistance;
|
||||
private final float mMinFlingVelocity;
|
||||
|
||||
private int mActivePointerId = -1;
|
||||
private float mDownY;
|
||||
private float mTotalY;
|
||||
|
||||
public AccessibilityInputConsumer(Context context, ISystemUiProxy systemUiProxy,
|
||||
boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor) {
|
||||
super(delegate, inputMonitor);
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mMinGestureDistance = context.getResources()
|
||||
.getDimension(R.dimen.accessibility_gesture_min_swipe_distance);
|
||||
mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
|
||||
|
||||
mMotionPauseDetector = new MotionPauseDetector(context);
|
||||
mAllowLongClick = allowLongClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_ACCESSIBILITY | mDelegate.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMotionEvent(MotionEvent ev) {
|
||||
if (mState != STATE_DELEGATE_ACTIVE) {
|
||||
mVelocityTracker.addMovement(ev);
|
||||
}
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case ACTION_DOWN: {
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_UP: {
|
||||
if (mState == STATE_ACTIVE) {
|
||||
int pointerIndex = ev.getActionIndex();
|
||||
int pointerId = ev.getPointerId(pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
final int newPointerIdx = pointerIndex == 0 ? 1 : 0;
|
||||
|
||||
mTotalY += (ev.getY(pointerIndex) - mDownY);
|
||||
mDownY = ev.getY(newPointerIdx);
|
||||
mActivePointerId = ev.getPointerId(newPointerIdx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_DOWN: {
|
||||
if (mState == STATE_INACTIVE) {
|
||||
if (mDelegate.allowInterceptByParent()) {
|
||||
setActive(ev);
|
||||
|
||||
int pointerIndex = ev.getActionIndex();
|
||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||
mDownY = ev.getY(pointerIndex);
|
||||
} else {
|
||||
mState = STATE_DELEGATE_ACTIVE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_MOVE: {
|
||||
if (mState == STATE_ACTIVE && mAllowLongClick) {
|
||||
int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
mMotionPauseDetector.addPosition(ev.getY(pointerIndex) - mDownY,
|
||||
ev.getEventTime());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_UP:
|
||||
if (mState == STATE_ACTIVE) {
|
||||
try {
|
||||
if (mAllowLongClick && mMotionPauseDetector.isPaused()) {
|
||||
mSystemUiProxy.notifyAccessibilityButtonLongClicked();
|
||||
} else {
|
||||
mTotalY += (ev.getY() - mDownY);
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
|
||||
if ((-mTotalY) > mMinGestureDistance
|
||||
|| (-mVelocityTracker.getYVelocity()) > mMinFlingVelocity) {
|
||||
mSystemUiProxy.notifyAccessibilityButtonClicked(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Unable to notify accessibility event", e);
|
||||
}
|
||||
}
|
||||
// Follow through
|
||||
case ACTION_CANCEL: {
|
||||
mVelocityTracker.recycle();
|
||||
mMotionPauseDetector.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState != STATE_ACTIVE) {
|
||||
mDelegate.onMotionEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -137,7 +137,7 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
|
||||
Rect targetRect = new Rect();
|
||||
mHelper.getSwipeUpDestinationAndLength(mActivity.getDeviceProfile(), mActivity, targetRect);
|
||||
clipHelper.updateTargetRect(targetRect);
|
||||
clipHelper.prepareAnimation(false /* isOpening */);
|
||||
clipHelper.prepareAnimation(mActivity.getDeviceProfile(), false /* isOpening */);
|
||||
|
||||
ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams()
|
||||
.setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(rootView));
|
||||
|
||||
+14
-52
@@ -50,20 +50,10 @@ import com.android.systemui.shared.system.QuickStepContract;
|
||||
/**
|
||||
* Touch consumer for handling events to launch assistant from launcher
|
||||
*/
|
||||
public class AssistantTouchConsumer implements InputConsumer {
|
||||
public class AssistantTouchConsumer extends DelegateInputConsumer {
|
||||
private static final String TAG = "AssistantTouchConsumer";
|
||||
private static final long RETRACT_ANIMATION_DURATION_MS = 300;
|
||||
|
||||
/* The assistant touch consume competes with quick switch InputConsumer gesture. The delegate
|
||||
* can be chosen to run if the angle passing the slop is lower than the threshold angle. When
|
||||
* this occurs, the state changes to {@link #STATE_DELEGATE_ACTIVE} where the next incoming
|
||||
* motion events are handled by the delegate instead of the assistant touch consumer. If the
|
||||
* angle is higher than the threshold, the state will change to {@link #STATE_ASSISTANT_ACTIVE}.
|
||||
*/
|
||||
private static final int STATE_INACTIVE = 0;
|
||||
private static final int STATE_ASSISTANT_ACTIVE = 1;
|
||||
private static final int STATE_DELEGATE_ACTIVE = 2;
|
||||
|
||||
private static final String INVOCATION_TYPE_KEY = "invocation_type";
|
||||
private static final int INVOCATION_TYPE_GESTURE = 1;
|
||||
|
||||
@@ -78,7 +68,6 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
private float mTimeFraction;
|
||||
private long mDragTime;
|
||||
private float mLastProgress;
|
||||
private int mState;
|
||||
private int mDirection;
|
||||
private ActivityControlHelper mActivityControlHelper;
|
||||
|
||||
@@ -87,46 +76,25 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
private final int mAngleThreshold;
|
||||
private final float mSlop;
|
||||
private final ISystemUiProxy mSysUiProxy;
|
||||
private final InputConsumer mConsumerDelegate;
|
||||
private final Context mContext;
|
||||
|
||||
private final InputMonitorCompat mInputMonitorCompat;
|
||||
|
||||
|
||||
public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy,
|
||||
InputConsumer delegate, InputMonitorCompat inputMonitorCompat,
|
||||
ActivityControlHelper activityControlHelper) {
|
||||
ActivityControlHelper activityControlHelper, InputConsumer delegate,
|
||||
InputMonitorCompat inputMonitor) {
|
||||
super(delegate, inputMonitor);
|
||||
final Resources res = context.getResources();
|
||||
mContext = context;
|
||||
mSysUiProxy = systemUiProxy;
|
||||
mConsumerDelegate = delegate;
|
||||
mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
|
||||
mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
|
||||
mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
|
||||
mSlop = QuickStepContract.getQuickStepDragSlopPx();
|
||||
mInputMonitorCompat = inputMonitorCompat;
|
||||
mActivityControlHelper = activityControlHelper;
|
||||
mState = STATE_INACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_ASSISTANT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSharedSwipeState() {
|
||||
if (mConsumerDelegate != null) {
|
||||
return mConsumerDelegate.useSharedSwipeState();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConsumerAboutToBeSwitched() {
|
||||
if (mConsumerDelegate != null) {
|
||||
mConsumerDelegate.onConsumerAboutToBeSwitched();
|
||||
}
|
||||
return TYPE_ASSISTANT | mDelegate.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,6 +126,10 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
if (mState == STATE_DELEGATE_ACTIVE) {
|
||||
break;
|
||||
}
|
||||
if (!mDelegate.allowInterceptByParent()) {
|
||||
mState = STATE_DELEGATE_ACTIVE;
|
||||
break;
|
||||
}
|
||||
int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) {
|
||||
break;
|
||||
@@ -168,9 +140,6 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
// Normal gesture, ensure we pass the slop before we start tracking the gesture
|
||||
if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) > mSlop) {
|
||||
|
||||
// Cancel touches to other windows (intercept)
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
|
||||
mPassedSlop = true;
|
||||
mStartDragPos.set(mLastPos.x, mLastPos.y);
|
||||
mDragTime = SystemClock.uptimeMillis();
|
||||
@@ -182,15 +151,7 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
angle = angle > 90 ? 180 - angle : angle;
|
||||
|
||||
if (angle > mAngleThreshold && angle < 90) {
|
||||
mState = STATE_ASSISTANT_ACTIVE;
|
||||
|
||||
if (mConsumerDelegate != null) {
|
||||
// Send cancel event
|
||||
MotionEvent event = MotionEvent.obtain(ev);
|
||||
event.setAction(MotionEvent.ACTION_CANCEL);
|
||||
mConsumerDelegate.onMotionEvent(event);
|
||||
event.recycle();
|
||||
}
|
||||
setActive(ev);
|
||||
} else {
|
||||
mState = STATE_DELEGATE_ACTIVE;
|
||||
}
|
||||
@@ -232,8 +193,8 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mState != STATE_ASSISTANT_ACTIVE && mConsumerDelegate != null) {
|
||||
mConsumerDelegate.onMotionEvent(ev);
|
||||
if (mState != STATE_ACTIVE) {
|
||||
mDelegate.onMotionEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +210,8 @@ public class AssistantTouchConsumer implements InputConsumer {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
|
||||
|
||||
BaseDraggingActivity launcherActivity = mActivityControlHelper.getCreatedActivity();
|
||||
BaseDraggingActivity launcherActivity =
|
||||
mActivityControlHelper.getCreatedActivity();
|
||||
if (launcherActivity != null) {
|
||||
launcherActivity.getRootView().
|
||||
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
public abstract class DelegateInputConsumer implements InputConsumer {
|
||||
|
||||
protected static final int STATE_INACTIVE = 0;
|
||||
protected static final int STATE_ACTIVE = 1;
|
||||
protected static final int STATE_DELEGATE_ACTIVE = 2;
|
||||
|
||||
protected final InputConsumer mDelegate;
|
||||
protected final InputMonitorCompat mInputMonitor;
|
||||
|
||||
protected int mState;
|
||||
|
||||
public DelegateInputConsumer(InputConsumer delegate, InputMonitorCompat inputMonitor) {
|
||||
mDelegate = delegate;
|
||||
mInputMonitor = inputMonitor;
|
||||
mState = STATE_INACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSharedSwipeState() {
|
||||
return mDelegate.useSharedSwipeState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInterceptByParent() {
|
||||
return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConsumerAboutToBeSwitched() {
|
||||
mDelegate.onConsumerAboutToBeSwitched();
|
||||
}
|
||||
|
||||
protected void setActive(MotionEvent ev) {
|
||||
mState = STATE_ACTIVE;
|
||||
mInputMonitor.pilferPointers();
|
||||
|
||||
// Send cancel event
|
||||
MotionEvent event = MotionEvent.obtain(ev);
|
||||
event.setAction(MotionEvent.ACTION_CANCEL);
|
||||
mDelegate.onMotionEvent(event);
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,12 @@ import android.view.MotionEvent;
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public interface InputConsumer {
|
||||
|
||||
int TYPE_NO_OP = 0;
|
||||
int TYPE_OVERVIEW = 1;
|
||||
int TYPE_OTHER_ACTIVITY = 2;
|
||||
int TYPE_ASSISTANT = 3;
|
||||
int TYPE_DEVICE_LOCKED = 4;
|
||||
int TYPE_NO_OP = 1 << 0;
|
||||
int TYPE_OVERVIEW = 1 << 1;
|
||||
int TYPE_OTHER_ACTIVITY = 1 << 2;
|
||||
int TYPE_ASSISTANT = 1 << 3;
|
||||
int TYPE_DEVICE_LOCKED = 1 << 4;
|
||||
int TYPE_ACCESSIBILITY = 1 << 5;
|
||||
|
||||
InputConsumer NO_OP = () -> TYPE_NO_OP;
|
||||
|
||||
@@ -38,6 +39,13 @@ public interface InputConsumer {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user has crossed the threshold for it to be an explicit action.
|
||||
*/
|
||||
default boolean allowInterceptByParent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the event queue when the consumer is about to be switched to a new consumer.
|
||||
*/
|
||||
|
||||
+11
-6
@@ -116,10 +116,12 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
} else {
|
||||
workspaceView = null;
|
||||
}
|
||||
final Rect iconLocation = new Rect();
|
||||
final FloatingIconView floatingView = workspaceView == null ? null
|
||||
: FloatingIconView.getFloatingIconView(activity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, null /* recycle */);
|
||||
final RectF iconLocation = new RectF();
|
||||
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
|
||||
final FloatingIconView floatingView = canUseWorkspaceView
|
||||
? FloatingIconView.getFloatingIconView(activity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, null /* recycle */)
|
||||
: null;
|
||||
|
||||
return new HomeAnimationFactory() {
|
||||
@Nullable
|
||||
@@ -135,8 +137,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
final float targetCenterX = dp.availableWidthPx / 2f;
|
||||
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
|
||||
|
||||
if (workspaceView != null) {
|
||||
return new RectF(iconLocation);
|
||||
if (canUseWorkspaceView) {
|
||||
return iconLocation;
|
||||
} else {
|
||||
// Fallback to animate to center of screen.
|
||||
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
|
||||
@@ -308,7 +310,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
SCALE_PROPERTY.set(recentsView, targetRvScale);
|
||||
recentsView.setTranslationY(0);
|
||||
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
|
||||
float tmpCurveScale = v.getCurveScale();
|
||||
v.setCurveScale(1f);
|
||||
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
|
||||
v.setCurveScale(tmpCurveScale);
|
||||
SCALE_PROPERTY.set(recentsView, prevRvScale);
|
||||
recentsView.setTranslationY(prevRvTransY);
|
||||
|
||||
|
||||
+42
-44
@@ -21,6 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
import static android.view.MotionEvent.INVALID_POINTER_ID;
|
||||
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
|
||||
@@ -34,20 +35,17 @@ import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.Display;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.RaceConditionTracker;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
@@ -61,10 +59,11 @@ import com.android.systemui.shared.system.BackgroundExecutor;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Input consumer for handling events originating from an activity other than Launcher
|
||||
*/
|
||||
@@ -80,14 +79,12 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
private final Intent mHomeIntent;
|
||||
private final ActivityControlHelper mActivityControlHelper;
|
||||
private final OverviewCallbacks mOverviewCallbacks;
|
||||
private final TaskOverlayFactory mTaskOverlayFactory;
|
||||
private final InputConsumerController mInputConsumer;
|
||||
private final SwipeSharedState mSwipeSharedState;
|
||||
private final InputMonitorCompat mInputMonitorCompat;
|
||||
private final SysUINavigationMode.Mode mMode;
|
||||
|
||||
private final int mDisplayRotation;
|
||||
private final Rect mStableInsets = new Rect();
|
||||
|
||||
private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
|
||||
private final MotionPauseDetector mMotionPauseDetector;
|
||||
@@ -122,7 +119,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo,
|
||||
RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
|
||||
boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks,
|
||||
TaskOverlayFactory taskOverlayFactory, InputConsumerController inputConsumer,
|
||||
InputConsumerController inputConsumer,
|
||||
Consumer<OtherActivityInputConsumer> onCompleteCallback,
|
||||
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat) {
|
||||
super(base);
|
||||
@@ -144,14 +141,10 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
|
||||
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
|
||||
mOverviewCallbacks = overviewCallbacks;
|
||||
mTaskOverlayFactory = taskOverlayFactory;
|
||||
mInputConsumer = inputConsumer;
|
||||
mSwipeSharedState = swipeSharedState;
|
||||
|
||||
Display display = getSystemService(WindowManager.class).getDefaultDisplay();
|
||||
mDisplayRotation = display.getRotation();
|
||||
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
|
||||
|
||||
mDisplayRotation = getSystemService(WindowManager.class).getDefaultDisplay().getRotation();
|
||||
mDragSlop = QuickStepContract.getQuickStepDragSlopPx();
|
||||
mTouchSlop = QuickStepContract.getQuickStepTouchSlopPx();
|
||||
|
||||
@@ -170,16 +163,17 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
}
|
||||
|
||||
// Proxy events to recents view
|
||||
if (!isNavBarOnLeft() && !isNavBarOnRight()) {
|
||||
if (mPassedDragSlop && mInteractionHandler != null
|
||||
&& !mRecentsViewDispatcher.hasConsumer()) {
|
||||
mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher());
|
||||
}
|
||||
int edgeFlags = ev.getEdgeFlags();
|
||||
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
|
||||
mRecentsViewDispatcher.dispatchEvent(ev);
|
||||
ev.setEdgeFlags(edgeFlags);
|
||||
if (mPassedDragSlop && mInteractionHandler != null
|
||||
&& !mRecentsViewDispatcher.hasConsumer()) {
|
||||
mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
|
||||
isNavBarOnLeft()
|
||||
? RotationMode.SEASCAPE
|
||||
: (isNavBarOnRight() ? RotationMode.LANDSCAPE : RotationMode.NORMAL)));
|
||||
}
|
||||
int edgeFlags = ev.getEdgeFlags();
|
||||
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
|
||||
mRecentsViewDispatcher.dispatchEvent(ev);
|
||||
ev.setEdgeFlags(edgeFlags);
|
||||
|
||||
mVelocityTracker.addMovement(ev);
|
||||
if (ev.getActionMasked() == ACTION_POINTER_UP) {
|
||||
@@ -301,13 +295,11 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
}
|
||||
|
||||
private boolean isNavBarOnRight() {
|
||||
return SysUINavigationMode.INSTANCE.get(getBaseContext()).getMode() != NO_BUTTON
|
||||
&& mDisplayRotation == Surface.ROTATION_90 && mStableInsets.right > 0;
|
||||
return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90;
|
||||
}
|
||||
|
||||
private boolean isNavBarOnLeft() {
|
||||
return SysUINavigationMode.INSTANCE.get(getBaseContext()).getMode() != NO_BUTTON
|
||||
&& mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
|
||||
return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270;
|
||||
}
|
||||
|
||||
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
|
||||
@@ -345,18 +337,21 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
*/
|
||||
private void finishTouchTracking(MotionEvent ev) {
|
||||
if (mPassedDragSlop && mInteractionHandler != null) {
|
||||
if (ev.getActionMasked() == ACTION_CANCEL) {
|
||||
mInteractionHandler.onGestureCancelled();
|
||||
} else {
|
||||
mVelocityTracker.computeCurrentVelocity(1000,
|
||||
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
|
||||
float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
|
||||
float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
|
||||
float velocity = isNavBarOnRight() ? velocityX
|
||||
: isNavBarOnLeft() ? -velocityX
|
||||
: velocityY;
|
||||
|
||||
mVelocityTracker.computeCurrentVelocity(1000,
|
||||
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
|
||||
float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
|
||||
float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
|
||||
float velocity = isNavBarOnRight() ? velocityX
|
||||
: isNavBarOnLeft() ? -velocityX
|
||||
: velocityY;
|
||||
|
||||
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
|
||||
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
|
||||
mDownPos);
|
||||
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
|
||||
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
|
||||
mDownPos);
|
||||
}
|
||||
} else {
|
||||
// Since we start touch tracking on DOWN, we may reach this state without actually
|
||||
// starting the gesture. In that case, just cleanup immediately.
|
||||
@@ -387,7 +382,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
mSwipeSharedState.canGestureBeContinued = endTarget != null && endTarget.canBeContinued;
|
||||
mSwipeSharedState.goingToLauncher = endTarget != null && endTarget.isLauncher;
|
||||
if (mSwipeSharedState.canGestureBeContinued) {
|
||||
mInteractionHandler.cancel();
|
||||
mInteractionHandler.cancelCurrentAnimation();
|
||||
} else {
|
||||
mInteractionHandler.reset();
|
||||
}
|
||||
@@ -410,19 +405,22 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
}
|
||||
|
||||
private float getDisplacement(MotionEvent ev) {
|
||||
float eventX = ev.getX();
|
||||
float eventY = ev.getY();
|
||||
float displacement = eventY - mDownPos.y;
|
||||
if (isNavBarOnRight()) {
|
||||
displacement = eventX - mDownPos.x;
|
||||
return ev.getX() - mDownPos.x;
|
||||
} else if (isNavBarOnLeft()) {
|
||||
displacement = mDownPos.x - eventX;
|
||||
return mDownPos.x - ev.getX();
|
||||
} else {
|
||||
return ev.getY() - mDownPos.y;
|
||||
}
|
||||
return displacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSharedSwipeState() {
|
||||
return mInteractionHandler != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInterceptByParent() {
|
||||
return !mPassedTouchSlop;
|
||||
}
|
||||
}
|
||||
|
||||
+50
-84
@@ -15,24 +15,22 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.util.CachedEventDispatcher;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Input consumer for handling touch on the recents/Launcher activity.
|
||||
@@ -40,24 +38,33 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
implements InputConsumer {
|
||||
|
||||
private final CachedEventDispatcher mCachedEventDispatcher = new CachedEventDispatcher();
|
||||
private final T mActivity;
|
||||
private final BaseDragLayer mTarget;
|
||||
private final InputMonitorCompat mInputMonitor;
|
||||
|
||||
private final int[] mLocationOnScreen = new int[2];
|
||||
private final PointF mDownPos = new PointF();
|
||||
private final int mTouchSlopSquared;
|
||||
private final boolean mProxyTouch;
|
||||
private final Predicate<MotionEvent> mEventReceiver;
|
||||
|
||||
private final boolean mStartingInActivityBounds;
|
||||
private boolean mTargetHandledTouch;
|
||||
|
||||
private boolean mTrackingStarted = false;
|
||||
private boolean mInvalidated = false;
|
||||
|
||||
OverviewInputConsumer(T activity, boolean startingInActivityBounds) {
|
||||
OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor,
|
||||
boolean startingInActivityBounds) {
|
||||
mActivity = activity;
|
||||
mTarget = activity.getDragLayer();
|
||||
int touchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
|
||||
mTouchSlopSquared = touchSlop * touchSlop;
|
||||
mInputMonitor = inputMonitor;
|
||||
mStartingInActivityBounds = startingInActivityBounds;
|
||||
|
||||
mTarget = activity.getDragLayer();
|
||||
if (startingInActivityBounds) {
|
||||
mEventReceiver = mTarget::dispatchTouchEvent;
|
||||
mProxyTouch = true;
|
||||
} else {
|
||||
// Only proxy touches to controllers if we are starting touch from nav bar.
|
||||
mEventReceiver = mTarget::proxyTouchEvent;
|
||||
mTarget.getLocationOnScreen(mLocationOnScreen);
|
||||
mProxyTouch = mTarget.prepareProxyEventStarting();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,47 +72,36 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
return TYPE_OVERVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInterceptByParent() {
|
||||
return !mTargetHandledTouch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMotionEvent(MotionEvent ev) {
|
||||
if (mInvalidated) {
|
||||
if (!mProxyTouch) {
|
||||
return;
|
||||
}
|
||||
mCachedEventDispatcher.dispatchEvent(ev);
|
||||
int action = ev.getActionMasked();
|
||||
if (action == ACTION_DOWN) {
|
||||
if (mStartingInActivityBounds) {
|
||||
startTouchTracking(ev, false /* updateLocationOffset */,
|
||||
false /* closeActiveWindows */);
|
||||
return;
|
||||
}
|
||||
mTrackingStarted = false;
|
||||
mDownPos.set(ev.getX(), ev.getY());
|
||||
} else if (!mTrackingStarted) {
|
||||
switch (action) {
|
||||
case ACTION_CANCEL:
|
||||
case ACTION_UP:
|
||||
startTouchTracking(ev, true /* updateLocationOffset */,
|
||||
false /* closeActiveWindows */);
|
||||
break;
|
||||
case ACTION_MOVE: {
|
||||
float x = ev.getX() - mDownPos.x;
|
||||
float y = ev.getY() - mDownPos.y;
|
||||
double hypotSquared = x * x + y * y;
|
||||
if (hypotSquared >= mTouchSlopSquared) {
|
||||
// Start tracking only when touch slop is crossed.
|
||||
startTouchTracking(ev, true /* updateLocationOffset */,
|
||||
true /* closeActiveWindows */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int flags = ev.getEdgeFlags();
|
||||
if (!mStartingInActivityBounds) {
|
||||
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
|
||||
}
|
||||
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
|
||||
boolean handled = mEventReceiver.test(ev);
|
||||
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
||||
ev.setEdgeFlags(flags);
|
||||
|
||||
if (action == ACTION_UP || action == ACTION_CANCEL) {
|
||||
mInvalidated = true;
|
||||
|
||||
// Set an empty consumer to that all the cached events are cleared
|
||||
if (!mCachedEventDispatcher.hasConsumer()) {
|
||||
mCachedEventDispatcher.setConsumer(motionEvent -> { });
|
||||
if (!mTargetHandledTouch && handled) {
|
||||
mTargetHandledTouch = true;
|
||||
if (!mStartingInActivityBounds) {
|
||||
OverviewCallbacks.get(mActivity).closeAllWindows();
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
TOUCH_INTERACTION_LOG.addLog("startQuickstep");
|
||||
}
|
||||
if (mInputMonitor != null) {
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,42 +113,12 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
private void startTouchTracking(MotionEvent ev, boolean updateLocationOffset,
|
||||
boolean closeActiveWindows) {
|
||||
if (updateLocationOffset) {
|
||||
mTarget.getLocationOnScreen(mLocationOnScreen);
|
||||
}
|
||||
|
||||
if (closeActiveWindows) {
|
||||
OverviewCallbacks.get(mActivity).closeAllWindows();
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
TOUCH_INTERACTION_LOG.addLog("startQuickstep");
|
||||
}
|
||||
|
||||
mTrackingStarted = true;
|
||||
mCachedEventDispatcher.setConsumer(this::sendEvent);
|
||||
|
||||
}
|
||||
|
||||
private void sendEvent(MotionEvent ev) {
|
||||
if (mInvalidated) {
|
||||
return;
|
||||
}
|
||||
int flags = ev.getEdgeFlags();
|
||||
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
|
||||
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
|
||||
mInvalidated = !mTarget.dispatchTouchEvent(this, ev);
|
||||
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
||||
ev.setEdgeFlags(flags);
|
||||
}
|
||||
|
||||
public static InputConsumer newInstance(ActivityControlHelper activityHelper,
|
||||
boolean startingInActivityBounds) {
|
||||
@Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) {
|
||||
BaseDraggingActivity activity = activityHelper.getCreatedActivity();
|
||||
if (activity == null) {
|
||||
return InputConsumer.NO_OP;
|
||||
}
|
||||
return new OverviewInputConsumer(activity, startingInActivityBounds);
|
||||
return new OverviewInputConsumer(activity, inputMonitor, startingInActivityBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,16 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
mLastAnimationRunning = true;
|
||||
}
|
||||
|
||||
private void clearAnimationTarget() {
|
||||
if (mLastAnimationTarget != null) {
|
||||
mLastAnimationTarget.release();
|
||||
mLastAnimationTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onRecentsAnimationCanceled() {
|
||||
mLastAnimationTarget = null;
|
||||
clearAnimationTarget();
|
||||
|
||||
mLastAnimationCancelled = true;
|
||||
mLastAnimationRunning = false;
|
||||
@@ -64,7 +71,7 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
mRecentsAnimationListener.removeListener(this);
|
||||
}
|
||||
mRecentsAnimationListener = null;
|
||||
mLastAnimationTarget = null;
|
||||
clearAnimationTarget();
|
||||
mLastAnimationCancelled = false;
|
||||
mLastAnimationRunning = false;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,18 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.ComponentName;
|
||||
import android.graphics.RectF;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
@@ -109,8 +114,14 @@ public final class TaskViewUtils {
|
||||
*/
|
||||
public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
|
||||
RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
|
||||
SyncRtSurfaceTransactionApplierCompat applier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(v);
|
||||
ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams()
|
||||
.setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(v));
|
||||
.setSyncTransactionApplier(applier);
|
||||
|
||||
final RemoteAnimationTargetSet targetSet =
|
||||
new RemoteAnimationTargetSet(targets, MODE_OPENING);
|
||||
targetSet.addDependentTransactionApplier(applier);
|
||||
|
||||
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
|
||||
@@ -120,17 +131,17 @@ public final class TaskViewUtils {
|
||||
final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
|
||||
final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);
|
||||
|
||||
final RemoteAnimationTargetSet mTargetSet;
|
||||
|
||||
final RectF mThumbnailRect;
|
||||
|
||||
{
|
||||
mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING);
|
||||
inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
|
||||
|
||||
inOutHelper.prepareAnimation(true /* isOpening */);
|
||||
inOutHelper.prepareAnimation(
|
||||
BaseActivity.fromContext(v.getContext()).getDeviceProfile(),
|
||||
true /* isOpening */);
|
||||
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
|
||||
mTargetSet.apps.length == 0 ? null : mTargetSet.apps[0]);
|
||||
targetSet.apps.length == 0 ? null : targetSet.apps[0]);
|
||||
|
||||
mThumbnailRect = new RectF(inOutHelper.getTargetRect());
|
||||
mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY());
|
||||
@@ -140,7 +151,7 @@ public final class TaskViewUtils {
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
params.setProgress(1 - percent);
|
||||
RectF taskBounds = inOutHelper.applyTransform(mTargetSet, params);
|
||||
RectF taskBounds = inOutHelper.applyTransform(targetSet, params);
|
||||
if (!skipViewChanges) {
|
||||
float scale = taskBounds.width() / mThumbnailRect.width();
|
||||
v.setScaleX(scale);
|
||||
@@ -151,6 +162,12 @@ public final class TaskViewUtils {
|
||||
}
|
||||
}
|
||||
});
|
||||
appAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
targetSet.release();
|
||||
}
|
||||
});
|
||||
return appAnimator;
|
||||
}
|
||||
}
|
||||
|
||||
+40
-22
@@ -20,15 +20,17 @@ import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -44,6 +46,7 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Choreographer;
|
||||
import android.view.Display;
|
||||
@@ -53,6 +56,7 @@ import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.logging.EventLogArray;
|
||||
@@ -67,9 +71,8 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -78,7 +81,7 @@ import java.util.List;
|
||||
/**
|
||||
* Service connected by system-UI for handling touch interaction.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class TouchInteractionService extends Service implements
|
||||
NavigationModeChangeListener, DisplayListener {
|
||||
|
||||
@@ -229,6 +232,7 @@ public class TouchInteractionService extends Service implements
|
||||
private Mode mMode = Mode.THREE_BUTTONS;
|
||||
private int mDefaultDisplayId;
|
||||
private final RectF mSwipeTouchRegion = new RectF();
|
||||
private ComponentName mGestureBlockingActivity;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@@ -250,6 +254,10 @@ public class TouchInteractionService extends Service implements
|
||||
|
||||
mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay()
|
||||
.getDisplayId();
|
||||
|
||||
String blockingActivity = getString(R.string.gesture_blocking_activity);
|
||||
mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null :
|
||||
ComponentName.unflattenFromString(blockingActivity);
|
||||
sConnected = true;
|
||||
}
|
||||
|
||||
@@ -435,9 +443,9 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
|
||||
private boolean isInValidSystemUiState() {
|
||||
return (mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0;
|
||||
return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
|
||||
&& !ActivityManagerWrapper.getInstance().isLockToAppActive();
|
||||
}
|
||||
|
||||
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
|
||||
@@ -456,25 +464,35 @@ public class TouchInteractionService extends Service implements
|
||||
final ActivityControlHelper activityControl =
|
||||
mOverviewComponentObserver.getActivityControlHelper();
|
||||
|
||||
InputConsumer base;
|
||||
if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) {
|
||||
return InputConsumer.NO_OP;
|
||||
} else if (mAssistantAvailable
|
||||
&& SysUINavigationMode.INSTANCE.get(this).getMode() == Mode.NO_BUTTON
|
||||
&& AssistantTouchConsumer.withinTouchRegion(this, event)) {
|
||||
|
||||
boolean addDelegate = !activityControl.isResumed();
|
||||
return new AssistantTouchConsumer(this, mISystemUiProxy, addDelegate ?
|
||||
createOtherActivityInputConsumer(event, runningTaskInfo) : null,
|
||||
mInputMonitorCompat, activityControl);
|
||||
|
||||
base = InputConsumer.NO_OP;
|
||||
} else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
|
||||
return OverviewInputConsumer.newInstance(activityControl, false);
|
||||
base = OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false);
|
||||
} else if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
|
||||
activityControl.isInLiveTileMode()) {
|
||||
return OverviewInputConsumer.newInstance(activityControl, false);
|
||||
base = OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false);
|
||||
} else if (mGestureBlockingActivity != null && runningTaskInfo != null
|
||||
&& mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
|
||||
base = InputConsumer.NO_OP;
|
||||
} else {
|
||||
return createOtherActivityInputConsumer(event, runningTaskInfo);
|
||||
base = createOtherActivityInputConsumer(event, runningTaskInfo);
|
||||
}
|
||||
|
||||
if (mMode == Mode.NO_BUTTON) {
|
||||
if (mAssistantAvailable && AssistantTouchConsumer.withinTouchRegion(this, event)) {
|
||||
base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base,
|
||||
mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
|
||||
base = new AccessibilityInputConsumer(this, mISystemUiProxy,
|
||||
(mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base,
|
||||
mInputMonitorCompat);
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event,
|
||||
@@ -484,8 +502,8 @@ public class TouchInteractionService extends Service implements
|
||||
boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event);
|
||||
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
|
||||
mOverviewComponentObserver.getOverviewIntent(), activityControl,
|
||||
shouldDefer, mOverviewCallbacks, mTaskOverlayFactory, mInputConsumer,
|
||||
this::onConsumerInactive, mSwipeSharedState, mInputMonitorCompat);
|
||||
shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
|
||||
mSwipeSharedState, mInputMonitorCompat);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+67
-21
@@ -77,6 +77,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -220,6 +221,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
protected GestureEndTarget mGestureEndTarget;
|
||||
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
|
||||
private RunningWindowAnim mRunningWindowAnim;
|
||||
private boolean mIsShelfPeeking;
|
||||
private DeviceProfile mDp;
|
||||
private int mTransitionDragLength;
|
||||
@@ -250,7 +253,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
private T mActivity;
|
||||
private RecentsView mRecentsView;
|
||||
private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
|
||||
private AnimationFactory mAnimationFactory = (t) -> { };
|
||||
private LiveTileOverlay mLiveTileOverlay = new LiveTileOverlay();
|
||||
|
||||
@@ -405,8 +407,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView,
|
||||
applier -> mSyncTransactionApplier = applier );
|
||||
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
|
||||
mTransformParams.setSyncTransactionApplier(applier);
|
||||
mRecentsAnimationWrapper.runOnInit(() ->
|
||||
mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier));
|
||||
});
|
||||
mRecentsView.setEnableFreeScroll(false);
|
||||
|
||||
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
|
||||
@@ -529,8 +534,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
return TaskView.getCurveScaleForInterpolation(interpolation);
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher() {
|
||||
return mRecentsView != null ? mRecentsView::dispatchTouchEvent : null;
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
|
||||
return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -648,8 +653,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
|
||||
mClipAnimationHelper.getTargetRect().width());
|
||||
mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale)
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier);
|
||||
mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
|
||||
mTransformParams);
|
||||
mRecentsAnimationWrapper.setWindowThresholdCrossed(
|
||||
@@ -729,7 +733,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
if (runningTaskTarget != null) {
|
||||
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
|
||||
}
|
||||
mClipAnimationHelper.prepareAnimation(false /* isOpening */);
|
||||
mClipAnimationHelper.prepareAnimation(dp, false /* isOpening */);
|
||||
initTransitionEndpoints(dp);
|
||||
|
||||
mRecentsAnimationWrapper.setController(targetSet);
|
||||
@@ -768,6 +772,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called as a result on ACTION_CANCEL to return the UI to the start state.
|
||||
*/
|
||||
@UiThread
|
||||
public void onGestureCancelled() {
|
||||
updateDisplacement(0);
|
||||
setStateOnUiThread(STATE_GESTURE_COMPLETED);
|
||||
mLogAction = Touch.SWIPE_NOOP;
|
||||
handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endVelocity The velocity in the direction of the nav bar to the middle of the screen.
|
||||
* @param velocity The x and y components of the velocity when the gesture ends.
|
||||
@@ -788,12 +803,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT;
|
||||
}
|
||||
mDownPos = downPos;
|
||||
handleNormalGestureEnd(endVelocity, isFling, velocity);
|
||||
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private InputConsumer createNewInputProxyHandler() {
|
||||
mCurrentShift.finishAnimation();
|
||||
endRunningWindowAnim();
|
||||
if (mLauncherTransitionController != null) {
|
||||
mLauncherTransitionController.getAnimationPlayer().end();
|
||||
}
|
||||
@@ -802,11 +817,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
|
||||
}
|
||||
|
||||
return OverviewInputConsumer.newInstance(mActivityControlHelper, true);
|
||||
return OverviewInputConsumer.newInstance(mActivityControlHelper, null, true);
|
||||
}
|
||||
|
||||
private void endRunningWindowAnim() {
|
||||
if (mRunningWindowAnim != null) {
|
||||
mRunningWindowAnim.end();
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity) {
|
||||
private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
|
||||
boolean isCancel) {
|
||||
PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
|
||||
long duration = MAX_SWIPE_DURATION;
|
||||
float currentShift = mCurrentShift.value;
|
||||
@@ -824,7 +846,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW;
|
||||
if (!isFling) {
|
||||
if (mMode == Mode.NO_BUTTON) {
|
||||
if (isCancel) {
|
||||
endTarget = LAST_TASK;
|
||||
} else if (mMode == Mode.NO_BUTTON) {
|
||||
if (mIsShelfPeeking) {
|
||||
endTarget = RECENTS;
|
||||
} else if (goingToNewTask) {
|
||||
@@ -883,12 +907,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
if (endTarget.isLauncher) {
|
||||
mRecentsAnimationWrapper.enableInputProxy();
|
||||
}
|
||||
|
||||
if (endTarget == HOME) {
|
||||
setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
|
||||
duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
|
||||
} else if (endTarget == RECENTS) {
|
||||
mLiveTileOverlay.startIconAnimation();
|
||||
mRecentsAnimationWrapper.enableInputProxy();
|
||||
if (mRecentsView != null) {
|
||||
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
|
||||
}
|
||||
@@ -907,7 +934,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
private void doLogGesture(GestureEndTarget endTarget) {
|
||||
DeviceProfile dp = mDp;
|
||||
if (dp == null) {
|
||||
if (dp == null || mDownPos == null) {
|
||||
// We probably never received an animation controller, skip logging.
|
||||
return;
|
||||
}
|
||||
@@ -969,6 +996,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
});
|
||||
windowAnim.start(velocityPxPerMs);
|
||||
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
||||
mLauncherTransitionController = null;
|
||||
} else {
|
||||
ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
|
||||
@@ -987,6 +1015,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
});
|
||||
windowAnim.start();
|
||||
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
||||
}
|
||||
// Always play the entire launcher animation when going home, since it is separate from
|
||||
// the animation that has been controlled thus far.
|
||||
@@ -1047,8 +1076,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
float iconAlpha = Utilities.mapToRange(interpolatedProgress, 0,
|
||||
windowAlphaThreshold, 0f, 1f, Interpolators.LINEAR);
|
||||
mTransformParams.setCurrentRectAndTargetAlpha(currentRect, 1f - iconAlpha)
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier);
|
||||
mTransformParams.setCurrentRectAndTargetAlpha(currentRect, 1f - iconAlpha);
|
||||
mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
|
||||
false /* launcherOnTop */);
|
||||
|
||||
@@ -1062,7 +1090,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
homeAnim.dispatchOnStart();
|
||||
mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
|
||||
if (mActivity != null) {
|
||||
mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1097,7 +1127,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
false /* animate */, true /* freezeTaskList */);
|
||||
});
|
||||
}
|
||||
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
|
||||
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
|
||||
doLogGesture(NEW_TASK);
|
||||
reset();
|
||||
}
|
||||
@@ -1106,7 +1136,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
setStateOnUiThread(STATE_HANDLER_INVALIDATED);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
/**
|
||||
* Cancels any running animation so that the active target can be overriden by a new swipe
|
||||
* handle (in case of quick switch).
|
||||
*/
|
||||
public void cancelCurrentAnimation() {
|
||||
mCurrentShift.cancelAnimation();
|
||||
if (mLauncherTransitionController != null && mLauncherTransitionController
|
||||
.getAnimationPlayer().isStarted()) {
|
||||
@@ -1115,7 +1149,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
private void invalidateHandler() {
|
||||
mCurrentShift.finishAnimation();
|
||||
endRunningWindowAnim();
|
||||
|
||||
if (mGestureEndCallback != null) {
|
||||
mGestureEndCallback.run();
|
||||
@@ -1263,4 +1297,16 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
return app.isNotInRecents
|
||||
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
|
||||
}
|
||||
|
||||
private interface RunningWindowAnim {
|
||||
void end();
|
||||
|
||||
static RunningWindowAnim wrap(Animator animator) {
|
||||
return animator::end;
|
||||
}
|
||||
|
||||
static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
|
||||
return rectFSpringAnim::end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-28
@@ -17,18 +17,13 @@ package com.android.quickstep.fallback;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
@@ -39,9 +34,6 @@ public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
|
||||
private static final int MIN_SIZE = 10;
|
||||
private final RecentsActivity mActivity;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private final RectF mTouchExcludeRegion = new RectF();
|
||||
|
||||
private final Point mLastKnownSize = new Point(MIN_SIZE, MIN_SIZE);
|
||||
|
||||
public RecentsRootView(Context context, AttributeSet attrs) {
|
||||
@@ -100,26 +92,7 @@ public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
|
||||
|
||||
@Override
|
||||
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
Insets gestureInsets = insets.getMandatorySystemGestureInsets();
|
||||
mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
|
||||
gestureInsets.right, gestureInsets.bottom);
|
||||
}
|
||||
updateTouchExcludeRegion(insets);
|
||||
return super.dispatchApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
float x = ev.getX();
|
||||
float y = ev.getY();
|
||||
if (y < mTouchExcludeRegion.top
|
||||
|| x < mTouchExcludeRegion.left
|
||||
|| x > (getWidth() - mTouchExcludeRegion.right)
|
||||
|| y > (getHeight() - mTouchExcludeRegion.bottom)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
+17
-7
@@ -31,11 +31,12 @@ import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
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;
|
||||
@@ -50,8 +51,6 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class to handle window clip animation
|
||||
*/
|
||||
@@ -81,6 +80,7 @@ public class ClipAnimationHelper {
|
||||
private final RectF mClipRectF = new RectF();
|
||||
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
|
||||
private final Matrix mTmpMatrix = new Matrix();
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final RectF mTmpRectF = new RectF();
|
||||
private final RectF mCurrentRectWithInsets = new RectF();
|
||||
// Corner radius of windows, in pixels
|
||||
@@ -89,6 +89,8 @@ public class ClipAnimationHelper {
|
||||
private final float mTaskCornerRadius;
|
||||
// If windows can have real time rounded corners.
|
||||
private final boolean mSupportsRoundedCornersOnWindows;
|
||||
// Whether or not to actually use the rounded cornders on windows
|
||||
private boolean mUseRoundedCornersOnWindows;
|
||||
|
||||
// Corner radius currently applied to transformed window.
|
||||
private float mCurrentCornerRadius;
|
||||
@@ -103,6 +105,7 @@ public class ClipAnimationHelper {
|
||||
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
|
||||
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
|
||||
mTaskCornerRadius = TaskCornerRadius.get(context);
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
|
||||
}
|
||||
|
||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||
@@ -144,8 +147,9 @@ public class ClipAnimationHelper {
|
||||
mSourceRect.set(scaledTargetRect);
|
||||
}
|
||||
|
||||
public void prepareAnimation(boolean isOpening) {
|
||||
public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
|
||||
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
|
||||
}
|
||||
|
||||
public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params) {
|
||||
@@ -177,7 +181,9 @@ public class ClipAnimationHelper {
|
||||
for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
|
||||
mTmpMatrix.setTranslate(app.position.x, app.position.y);
|
||||
Rect crop = app.sourceContainerBounds;
|
||||
Rect crop = mTmpRect;
|
||||
crop.set(app.sourceContainerBounds);
|
||||
crop.offsetTo(0, 0);
|
||||
float alpha = 1f;
|
||||
int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers);
|
||||
float cornerRadius = 0f;
|
||||
@@ -188,7 +194,9 @@ public class ClipAnimationHelper {
|
||||
mTmpMatrix.postTranslate(app.position.x, app.position.y);
|
||||
mClipRectF.roundOut(crop);
|
||||
if (mSupportsRoundedCornersOnWindows) {
|
||||
cornerRadius = Utilities.mapRange(params.progress, mWindowCornerRadius,
|
||||
float windowCornerRadius = mUseRoundedCornersOnWindows
|
||||
? mWindowCornerRadius : 0;
|
||||
cornerRadius = Utilities.mapRange(params.progress, windowCornerRadius,
|
||||
mTaskCornerRadius);
|
||||
mCurrentCornerRadius = cornerRadius;
|
||||
}
|
||||
@@ -318,12 +326,14 @@ public class ClipAnimationHelper {
|
||||
|
||||
float scale = mTargetRect.width() / mSourceRect.width();
|
||||
float insetProgress = (1 - progress);
|
||||
float windowCornerRadius = mUseRoundedCornersOnWindows
|
||||
? mWindowCornerRadius : 0;
|
||||
ttv.drawOnCanvas(canvas,
|
||||
-mSourceWindowClipInsets.left * insetProgress,
|
||||
-mSourceWindowClipInsets.top * insetProgress,
|
||||
ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
|
||||
ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
|
||||
Utilities.mapRange(progress, mWindowCornerRadius * scale, ttv.getCornerRadius()));
|
||||
Utilities.mapRange(progress, windowCornerRadius * scale, ttv.getCornerRadius()));
|
||||
}
|
||||
|
||||
public RectF getTargetRect() {
|
||||
|
||||
+25
-11
@@ -23,6 +23,9 @@ import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.FlingSpringAnim;
|
||||
@@ -30,9 +33,6 @@ import com.android.launcher3.anim.FlingSpringAnim;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
|
||||
/**
|
||||
* Applies spring forces to animate from a starting rect to a target rect,
|
||||
* while providing update callbacks to the caller.
|
||||
@@ -98,6 +98,10 @@ public class RectFSpringAnim {
|
||||
private float mCurrentCenterX;
|
||||
private float mCurrentCenterY;
|
||||
private float mCurrentScaleProgress;
|
||||
private FlingSpringAnim mRectXAnim;
|
||||
private FlingSpringAnim mRectYAnim;
|
||||
private ValueAnimator mRectScaleAnim;
|
||||
private boolean mAnimsStarted;
|
||||
private boolean mRectXAnimEnded;
|
||||
private boolean mRectYAnimEnded;
|
||||
private boolean mRectScaleAnimEnded;
|
||||
@@ -127,15 +131,15 @@ public class RectFSpringAnim {
|
||||
mRectYAnimEnded = true;
|
||||
maybeOnEnd();
|
||||
});
|
||||
FlingSpringAnim rectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, mCurrentCenterX,
|
||||
mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, mCurrentCenterX,
|
||||
mTargetRect.centerX(), velocityPxPerMs.x * 1000, onXEndListener);
|
||||
FlingSpringAnim rectYAnim = new FlingSpringAnim(this, RECT_CENTER_Y, mCurrentCenterY,
|
||||
mRectYAnim = new FlingSpringAnim(this, RECT_CENTER_Y, mCurrentCenterY,
|
||||
mTargetRect.centerY(), velocityPxPerMs.y * 1000, onYEndListener);
|
||||
|
||||
ValueAnimator rectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
|
||||
mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
|
||||
PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
|
||||
.setDuration(RECT_SCALE_DURATION);
|
||||
rectScaleAnim.addListener(new AnimationSuccessListener() {
|
||||
mRectScaleAnim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mRectScaleAnimEnded = true;
|
||||
@@ -143,14 +147,23 @@ public class RectFSpringAnim {
|
||||
}
|
||||
});
|
||||
|
||||
rectXAnim.start();
|
||||
rectYAnim.start();
|
||||
rectScaleAnim.start();
|
||||
mRectXAnim.start();
|
||||
mRectYAnim.start();
|
||||
mRectScaleAnim.start();
|
||||
mAnimsStarted = true;
|
||||
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
||||
animatorListener.onAnimationStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (mAnimsStarted) {
|
||||
mRectXAnim.end();
|
||||
mRectYAnim.end();
|
||||
mRectScaleAnim.end();
|
||||
}
|
||||
}
|
||||
|
||||
private void onUpdate() {
|
||||
if (!mOnUpdateListeners.isEmpty()) {
|
||||
float currentWidth = Utilities.mapRange(mCurrentScaleProgress, mStartRect.width(),
|
||||
@@ -166,7 +179,8 @@ public class RectFSpringAnim {
|
||||
}
|
||||
|
||||
private void maybeOnEnd() {
|
||||
if (mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded) {
|
||||
if (mAnimsStarted && mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded) {
|
||||
mAnimsStarted = false;
|
||||
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
|
||||
animatorListener.onAnimationEnd(null);
|
||||
}
|
||||
|
||||
-5
@@ -95,9 +95,4 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
|
||||
|
||||
void onRecentsAnimationCanceled();
|
||||
}
|
||||
|
||||
public interface SwipeAnimationFinishListener {
|
||||
|
||||
void onSwipeAnimationFinished(SwipeAnimationTargetSet targetSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
@@ -52,7 +53,7 @@ public class TaskViewDrawable extends Drawable {
|
||||
|
||||
private final RecentsView mParent;
|
||||
private final View mIconView;
|
||||
private final int[] mIconPos;
|
||||
private final float[] mIconPos;
|
||||
private final TaskView mTaskView;
|
||||
|
||||
private final TaskThumbnailView mThumbnailView;
|
||||
@@ -68,13 +69,15 @@ public class TaskViewDrawable extends Drawable {
|
||||
mParent = parent;
|
||||
mTaskView = tv;
|
||||
mIconView = tv.getIconView();
|
||||
mIconPos = new int[2];
|
||||
mIconPos = new float[2];
|
||||
mIconScale = mIconView.getScaleX();
|
||||
Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
|
||||
|
||||
mThumbnailView = tv.getThumbnail();
|
||||
mClipAnimationHelper = new ClipAnimationHelper(parent.getContext());
|
||||
mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
|
||||
mClipAnimationHelper.prepareAnimation(
|
||||
BaseActivity.fromContext(tv.getContext()).getDeviceProfile(), true /* isOpening */);
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
|
||||
@@ -45,6 +45,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
@@ -70,9 +71,6 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
@@ -85,6 +83,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PropertyListBuilder;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -111,6 +110,9 @@ import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
/**
|
||||
* A list of recent tasks.
|
||||
*/
|
||||
@@ -1639,4 +1641,26 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
public ClearAllButton getClearAllButton() {
|
||||
return mClearAllButton;
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getEventDispatcher(RotationMode rotationMode) {
|
||||
if (rotationMode.isTransposed) {
|
||||
Matrix transform = new Matrix();
|
||||
transform.setRotate(-rotationMode.surfaceRotation);
|
||||
|
||||
if (getWidth() > 0 && getHeight() > 0) {
|
||||
float scale = ((float) getWidth()) / getHeight();
|
||||
transform.postScale(scale, 1 / scale);
|
||||
}
|
||||
|
||||
Matrix inverse = new Matrix();
|
||||
transform.invert(inverse);
|
||||
return e -> {
|
||||
e.transform(transform);
|
||||
super.onTouchEvent(e);
|
||||
e.transform(inverse);
|
||||
};
|
||||
} else {
|
||||
return super::onTouchEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -51,7 +51,6 @@ import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
|
||||
import com.android.quickstep.util.TaskCornerRadius;
|
||||
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.
|
||||
@@ -60,6 +59,7 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
private final static ColorMatrix COLOR_MATRIX = new ColorMatrix();
|
||||
private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
|
||||
private final static Rect EMPTY_RECT = new Rect();
|
||||
|
||||
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
|
||||
new FloatProperty<TaskThumbnailView>("dimAlpha") {
|
||||
@@ -79,16 +79,17 @@ public class TaskThumbnailView extends View {
|
||||
private final BaseActivity mActivity;
|
||||
private final TaskOverlay mOverlay;
|
||||
private final boolean mIsDarkTextTheme;
|
||||
private final Paint mPaint = new Paint();
|
||||
private final Paint mBackgroundPaint = new Paint();
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final Paint mClearPaint = new Paint();
|
||||
private final Paint mDimmingPaintAfterClearing = new Paint();
|
||||
private final float mWindowCornerRadius;
|
||||
|
||||
private final Matrix mMatrix = new Matrix();
|
||||
|
||||
private float mClipBottom = -1;
|
||||
private Rect mScaledInsets = new Rect();
|
||||
private Rect mCurrentDrawnInsets = new Rect();
|
||||
private float mCurrentDrawnCornerRadius;
|
||||
private boolean mIsRotated;
|
||||
|
||||
private Task mTask;
|
||||
@@ -117,7 +118,7 @@ public class TaskThumbnailView extends View {
|
||||
mDimmingPaintAfterClearing.setColor(Color.BLACK);
|
||||
mActivity = BaseActivity.fromContext(context);
|
||||
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
|
||||
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
|
||||
setCurrentDrawnInsetsAndRadius(EMPTY_RECT, mCornerRadius);
|
||||
}
|
||||
|
||||
public void bind(Task task) {
|
||||
@@ -200,25 +201,24 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
TaskView taskView = (TaskView) getParent();
|
||||
float fullscreenProgress = taskView.getFullscreenProgress();
|
||||
if (mIsRotated) {
|
||||
// Don't show insets in the wrong orientation.
|
||||
fullscreenProgress = 0;
|
||||
}
|
||||
if (fullscreenProgress > 0) {
|
||||
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
|
||||
float cornerRadius = Utilities.mapRange(fullscreenProgress, mCornerRadius,
|
||||
mWindowCornerRadius);
|
||||
drawOnCanvas(canvas,
|
||||
-mScaledInsets.left * fullscreenProgress,
|
||||
-mScaledInsets.top * fullscreenProgress,
|
||||
getMeasuredWidth() + mScaledInsets.right * fullscreenProgress,
|
||||
getMeasuredHeight() + mScaledInsets.bottom * fullscreenProgress,
|
||||
cornerRadius / taskView.getRecentsView().getScaleX());
|
||||
} else {
|
||||
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
|
||||
}
|
||||
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
|
||||
drawOnCanvas(canvas,
|
||||
-mCurrentDrawnInsets.left,
|
||||
-mCurrentDrawnInsets.top,
|
||||
getMeasuredWidth() + mCurrentDrawnInsets.right,
|
||||
getMeasuredHeight() + mCurrentDrawnInsets.bottom,
|
||||
mCurrentDrawnCornerRadius);
|
||||
}
|
||||
|
||||
public Rect getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
|
||||
// Don't show insets in the wrong orientation or in multi window mode.
|
||||
return mIsRotated || isMultiWindowMode ? EMPTY_RECT : mScaledInsets;
|
||||
}
|
||||
|
||||
public void setCurrentDrawnInsetsAndRadius(Rect insets, float radius) {
|
||||
mCurrentDrawnInsets.set(insets);
|
||||
mCurrentDrawnCornerRadius = radius;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getCornerRadius() {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static com.android.launcher3.BaseActivity.fromContext;
|
||||
|
||||
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
@@ -31,6 +31,7 @@ import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -46,6 +47,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
@@ -53,7 +55,6 @@ import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
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;
|
||||
@@ -61,12 +62,15 @@ import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskSystemShortcut;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.util.TaskCornerRadius;
|
||||
import com.android.quickstep.views.RecentsView.PageCallbacks;
|
||||
import com.android.quickstep.views.RecentsView.ScrollState;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -95,6 +99,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
public static final long SCALE_ICON_DURATION = 120;
|
||||
private static final long DIM_ANIM_DURATION = 700;
|
||||
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
|
||||
public static final Property<TaskView, Float> ZOOM_SCALE =
|
||||
new FloatProperty<TaskView>("zoomScale") {
|
||||
@Override
|
||||
@@ -149,6 +156,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
}
|
||||
};
|
||||
|
||||
private final TaskOutlineProvider mOutlineProvider;
|
||||
|
||||
private Task mTask;
|
||||
private TaskThumbnailView mSnapshotView;
|
||||
private TaskMenuView mMenuView;
|
||||
@@ -157,6 +166,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private float mFullscreenProgress;
|
||||
private final Rect mCurrentDrawnInsets = new Rect();
|
||||
private final float mCornerRadius;
|
||||
private final float mWindowCornerRadius;
|
||||
private final BaseDraggingActivity mActivity;
|
||||
|
||||
private ObjectAnimator mIconAndDimAnimator;
|
||||
private float mIconScaleAnimStartProgress = 0;
|
||||
@@ -178,6 +191,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
|
||||
public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mActivity = BaseDraggingActivity.fromContext(context);
|
||||
setOnClickListener((view) -> {
|
||||
if (getTask() == null) {
|
||||
return;
|
||||
@@ -192,13 +206,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
launchTask(true /* animate */);
|
||||
}
|
||||
|
||||
fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
|
||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||
fromContext(context).getStatsLogManager().logTaskLaunch(getRecentsView(),
|
||||
mActivity.getStatsLogManager().logTaskLaunch(getRecentsView(),
|
||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||
});
|
||||
setOutlineProvider(new TaskOutlineProvider(context, getResources()));
|
||||
mCornerRadius = TaskCornerRadius.get(context);
|
||||
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
|
||||
mOutlineProvider = new TaskOutlineProvider(getResources(), mCornerRadius);
|
||||
setOutlineProvider(mOutlineProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,8 +308,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
if (mTask != null) {
|
||||
final ActivityOptions opts;
|
||||
if (animate) {
|
||||
opts = ((BaseDraggingActivity) fromContext(getContext()))
|
||||
.getActivityLaunchOptions(this);
|
||||
opts = mActivity.getActivityLaunchOptions(this);
|
||||
if (freezeTaskList) {
|
||||
ActivityOptionsCompat.setFreezeRecentTasksList(opts);
|
||||
}
|
||||
@@ -480,6 +496,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
setPivotX((right - left) * 0.5f);
|
||||
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
|
||||
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getCurveScaleForInterpolation(float linearInterpolation) {
|
||||
@@ -491,7 +511,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
|
||||
}
|
||||
|
||||
private void setCurveScale(float curveScale) {
|
||||
public void setCurveScale(float curveScale) {
|
||||
mCurveScale = curveScale;
|
||||
onScaleChanged();
|
||||
}
|
||||
@@ -520,17 +540,26 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private static final class TaskOutlineProvider extends ViewOutlineProvider {
|
||||
|
||||
private final int mMarginTop;
|
||||
private final float mRadius;
|
||||
private final Rect mInsets = new Rect();
|
||||
private float mRadius;
|
||||
|
||||
TaskOutlineProvider(Context context, Resources res) {
|
||||
TaskOutlineProvider(Resources res, float radius) {
|
||||
mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
||||
mRadius = Themes.getDialogCornerRadius(context);
|
||||
mRadius = radius;
|
||||
}
|
||||
|
||||
public void setCurrentDrawnInsetsAndRadius(Rect insets, float radius) {
|
||||
mInsets.set(insets);
|
||||
mRadius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setRoundRect(0, mMarginTop, view.getWidth(),
|
||||
view.getHeight(), mRadius);
|
||||
outline.setRoundRect(-mInsets.left,
|
||||
mMarginTop - mInsets.top,
|
||||
view.getWidth() + mInsets.right,
|
||||
view.getHeight() + mInsets.bottom,
|
||||
mRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,13 +572,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
getContext().getText(R.string.accessibility_close_task)));
|
||||
|
||||
final Context context = getContext();
|
||||
final BaseDraggingActivity activity = fromContext(context);
|
||||
final List<TaskSystemShortcut> shortcuts =
|
||||
mSnapshotView.getTaskOverlay().getEnabledShortcuts(this);
|
||||
final int count = shortcuts.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final TaskSystemShortcut menuOption = shortcuts.get(i);
|
||||
OnClickListener onClickListener = menuOption.getOnClickListener(activity, this);
|
||||
OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, this);
|
||||
if (onClickListener != null) {
|
||||
info.addAction(menuOption.createAccessibilityAction(context));
|
||||
}
|
||||
@@ -589,8 +617,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final TaskSystemShortcut menuOption = shortcuts.get(i);
|
||||
if (menuOption.hasHandlerForAction(action)) {
|
||||
OnClickListener onClickListener = menuOption.getOnClickListener(
|
||||
fromContext(getContext()), this);
|
||||
OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, this);
|
||||
if (onClickListener != null) {
|
||||
onClickListener.onClick(this);
|
||||
}
|
||||
@@ -628,11 +655,21 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
||||
setClipChildren(!isFullscreen);
|
||||
setClipToPadding(!isFullscreen);
|
||||
getThumbnail().invalidate();
|
||||
}
|
||||
|
||||
public float getFullscreenProgress() {
|
||||
return mFullscreenProgress;
|
||||
TaskThumbnailView thumbnail = getThumbnail();
|
||||
boolean isMultiWindowMode = mActivity.getDeviceProfile().isMultiWindowMode;
|
||||
Rect insets = thumbnail.getInsetsToDrawInFullscreen(isMultiWindowMode);
|
||||
mCurrentDrawnInsets.set((int) (insets.left * mFullscreenProgress),
|
||||
(int) (insets.top * mFullscreenProgress),
|
||||
(int) (insets.right * mFullscreenProgress),
|
||||
(int) (insets.bottom * mFullscreenProgress));
|
||||
float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius;
|
||||
float cornerRadius = Utilities.mapRange(mFullscreenProgress, mCornerRadius,
|
||||
fullscreenCornerRadius) / getRecentsView().getScaleX();
|
||||
|
||||
thumbnail.setCurrentDrawnInsetsAndRadius(mCurrentDrawnInsets, cornerRadius);
|
||||
mOutlineProvider.setCurrentDrawnInsetsAndRadius(mCurrentDrawnInsets, cornerRadius);
|
||||
invalidateOutline();
|
||||
}
|
||||
|
||||
public boolean isRunningTask() {
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
<string name="overview_callbacks_class" translatable="false"></string>
|
||||
|
||||
<!-- Activity which blocks home gesture -->
|
||||
<string name="gesture_blocking_activity" translatable="false"></string>
|
||||
|
||||
<string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
|
||||
|
||||
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
|
||||
|
||||
@@ -408,7 +408,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
*/
|
||||
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
|
||||
Rect windowTargetBounds, boolean toggleVisibility) {
|
||||
Rect bounds = new Rect();
|
||||
RectF bounds = new RectF();
|
||||
mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
|
||||
bounds, true /* isOpening */, mFloatingView);
|
||||
Rect crop = new Rect();
|
||||
@@ -416,17 +416,15 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
|
||||
RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
|
||||
MODE_OPENING);
|
||||
RemoteAnimationTargetSet closingTargets = new RemoteAnimationTargetSet(targets,
|
||||
MODE_CLOSING);
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
|
||||
openingTargets.addDependentTransactionApplier(surfaceApplier);
|
||||
|
||||
// Scale the app icon to take up the entire screen. This simplifies the math when
|
||||
// animating the app window position / scale.
|
||||
float maxScaleX = windowTargetBounds.width() / (float) bounds.width();
|
||||
// We use windowTargetBounds.width for scaleY too since we start off the animation where the
|
||||
// window is clipped to a square.
|
||||
float maxScaleY = windowTargetBounds.width() / (float) bounds.height();
|
||||
float smallestSize = Math.min(windowTargetBounds.height(), windowTargetBounds.width());
|
||||
float maxScaleX = smallestSize / bounds.width();
|
||||
float maxScaleY = smallestSize / bounds.height();
|
||||
float scale = Math.max(maxScaleX, maxScaleY);
|
||||
float startScale = 1f;
|
||||
if (v instanceof BubbleTextView && !(v.getParent() instanceof DeepShortcutView)) {
|
||||
@@ -470,6 +468,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
if (v instanceof BubbleTextView) {
|
||||
((BubbleTextView) v).setStayPressed(false);
|
||||
}
|
||||
openingTargets.release();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -111,14 +111,6 @@ public class TestInformationProvider extends ContentProvider {
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) distance);
|
||||
break;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_ENABLE_DRAG_LOGGING:
|
||||
TestProtocol.sDebugTracing = true;
|
||||
break;
|
||||
|
||||
case TestProtocol.REQUEST_DISABLE_DRAG_LOGGING:
|
||||
TestProtocol.sDebugTracing = false;
|
||||
break;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,20 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* Holds a collection of RemoteAnimationTargets, filtered by different properties.
|
||||
*/
|
||||
public class RemoteAnimationTargetSet {
|
||||
|
||||
private final Queue<SyncRtSurfaceTransactionApplierCompat> mDependentTransactionAppliers =
|
||||
new ArrayDeque<>(1);
|
||||
|
||||
public final RemoteAnimationTargetCompat[] unfilteredApps;
|
||||
public final RemoteAnimationTargetCompat[] apps;
|
||||
public final int targetMode;
|
||||
@@ -60,4 +66,19 @@ public class RemoteAnimationTargetSet {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addDependentTransactionApplier(SyncRtSurfaceTransactionApplierCompat delay) {
|
||||
mDependentTransactionAppliers.add(delay);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
SyncRtSurfaceTransactionApplierCompat applier = mDependentTransactionAppliers.poll();
|
||||
if (applier == null) {
|
||||
for (RemoteAnimationTargetCompat target : unfilteredApps) {
|
||||
target.release();
|
||||
}
|
||||
} else {
|
||||
applier.addAfterApplyCallback(this::release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
@@ -25,7 +26,9 @@ import android.content.ComponentName;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.os.Process;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -37,20 +40,16 @@ import com.android.launcher3.model.AppLaunchTracker;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
private static final int DEFAULT_APP_LAUNCH_TIMES = 3;
|
||||
private static final String TAG = "AppPredictionsUITests";
|
||||
public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
|
||||
private LauncherActivityInfo mSampleApp1;
|
||||
private LauncherActivityInfo mSampleApp2;
|
||||
@@ -86,24 +85,20 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
* Test that prediction UI is updated as soon as we get predictions from the system
|
||||
*/
|
||||
@Test
|
||||
@Ignore // b/131772711: this really fails (when being run as a part of the whole test suite)!
|
||||
public void testPredictionExistsInAllApps() {
|
||||
mActivityMonitor.startLauncher();
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
|
||||
// There has not been any update, verify that progress bar is showing
|
||||
waitForLauncherCondition("Prediction is not in loading state", launcher -> {
|
||||
ProgressBar p = findLoadingBar(launcher);
|
||||
return p != null && p.isShown();
|
||||
});
|
||||
|
||||
// Dispatch an update
|
||||
sendPredictionUpdate(mSampleApp1, mSampleApp2);
|
||||
// The first update should apply immediately.
|
||||
waitForLauncherCondition("Predictions were not updated in loading state",
|
||||
launcher -> getPredictedApp(launcher).size() == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tat prediction update is deferred if it is already visible
|
||||
* Test that prediction update is deferred if it is already visible
|
||||
*/
|
||||
@Test
|
||||
public void testPredictionsDeferredUntilHome() {
|
||||
@@ -122,6 +117,20 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
assertEquals(3, getFromLauncher(this::getPredictedApp).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // b/131772711 - this was failing in the lab
|
||||
public void testPredictionsDisabled() {
|
||||
mActivityMonitor.startLauncher();
|
||||
sendPredictionUpdate();
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
|
||||
waitForLauncherCondition("Predictions were not updated in loading state",
|
||||
launcher -> launcher.getAppsView().getFloatingHeaderView()
|
||||
.findFixedRowByType(PredictionRowView.class).getVisibility() == View.GONE);
|
||||
assertFalse(PredictionUiStateManager.INSTANCE.get(mTargetContext)
|
||||
.getCurrentState().isEnabled);
|
||||
}
|
||||
|
||||
public ArrayList<BubbleTextView> getPredictedApp(Launcher launcher) {
|
||||
PredictionRowView container = launcher.getAppsView().getFloatingHeaderView()
|
||||
.findFixedRowByType(PredictionRowView.class);
|
||||
@@ -136,20 +145,6 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
return predictedAppViews;
|
||||
}
|
||||
|
||||
private ProgressBar findLoadingBar(Launcher launcher) {
|
||||
PredictionRowView container = launcher.getAppsView().getFloatingHeaderView()
|
||||
.findFixedRowByType(PredictionRowView.class);
|
||||
|
||||
for (int i = 0; i < container.getChildCount(); i++) {
|
||||
View view = container.getChildAt(i);
|
||||
if (view instanceof ProgressBar) {
|
||||
return (ProgressBar) view;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void sendPredictionUpdate(LauncherActivityInfo... activities) {
|
||||
getOnUiThread(() -> {
|
||||
List<AppTarget> targets = new ArrayList<>(activities.length);
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.testcomponent.TestCommandReceiver;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
@@ -97,6 +98,7 @@ public class FallbackRecentsTest {
|
||||
|
||||
@NavigationModeSwitch(mode = THREE_BUTTON)
|
||||
@Test
|
||||
@Ignore // b/131630813
|
||||
public void goToOverviewFromHome() {
|
||||
mDevice.pressHome();
|
||||
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
|
||||
@@ -107,6 +109,7 @@ public class FallbackRecentsTest {
|
||||
|
||||
@NavigationModeSwitch(mode = THREE_BUTTON)
|
||||
@Test
|
||||
@Ignore // b/131630813
|
||||
public void goToOverviewFromApp() {
|
||||
startAppFast("com.android.settings");
|
||||
|
||||
|
||||
@@ -71,7 +71,8 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
if (TestHelpers.isInLauncherProcess() &&
|
||||
// b/130558787; b/131419978
|
||||
if (false && TestHelpers.isInLauncherProcess() &&
|
||||
description.getAnnotation(NavigationModeSwitch.class) != null) {
|
||||
Mode mode = description.getAnnotation(NavigationModeSwitch.class).mode();
|
||||
return new Statement() {
|
||||
|
||||
@@ -64,7 +64,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
private void startTestApps() throws Exception {
|
||||
startAppFast(getAppPackageName());
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS));
|
||||
startTestActivity(2);
|
||||
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
@@ -130,8 +130,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
|
||||
assertNotNull("overview.getCurrentTask() returned null (1)", task);
|
||||
assertNotNull("OverviewTask.open returned null", task.open());
|
||||
assertTrue("Contacts app didn't open from Overview", mDevice.wait(Until.hasObject(
|
||||
By.pkg(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS)).depth(0)),
|
||||
assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject(
|
||||
By.pkg(getAppPackageName()).text("TestActivity2")),
|
||||
LONG_WAIT_TIME_MS));
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.uioverrides.DisplayRotationListener;
|
||||
import com.android.launcher3.uioverrides.WallpaperColorInfo;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -69,7 +70,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
// Update theme
|
||||
WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
|
||||
wallpaperColorInfo.addOnChangeListener(this);
|
||||
int themeRes = getThemeRes(wallpaperColorInfo);
|
||||
int themeRes = Themes.getActivityThemeRes(this);
|
||||
if (themeRes != mThemeRes) {
|
||||
mThemeRes = themeRes;
|
||||
setTheme(themeRes);
|
||||
@@ -88,31 +89,11 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
}
|
||||
|
||||
private void updateTheme() {
|
||||
WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
|
||||
if (mThemeRes != getThemeRes(wallpaperColorInfo)) {
|
||||
if (mThemeRes != Themes.getActivityThemeRes(this)) {
|
||||
recreate();
|
||||
}
|
||||
}
|
||||
|
||||
protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) {
|
||||
boolean darkTheme;
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
Configuration configuration = getResources().getConfiguration();
|
||||
int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
|
||||
} else {
|
||||
darkTheme = wallpaperColorInfo.isDark();
|
||||
}
|
||||
|
||||
if (darkTheme) {
|
||||
return wallpaperColorInfo.supportsDarkText() ?
|
||||
R.style.AppTheme_Dark_DarkText : R.style.AppTheme_Dark;
|
||||
} else {
|
||||
return wallpaperColorInfo.supportsDarkText() ?
|
||||
R.style.AppTheme_DarkText : R.style.AppTheme;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {
|
||||
super.onActionModeStarted(mode);
|
||||
|
||||
@@ -123,12 +123,12 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||
* @param ev MotionEvent in {@param eventSource}
|
||||
*/
|
||||
public boolean shouldContainerScroll(MotionEvent ev, View eventSource) {
|
||||
int[] point = new int[2];
|
||||
point[0] = (int) ev.getX();
|
||||
point[1] = (int) ev.getY();
|
||||
float[] point = new float[2];
|
||||
point[0] = ev.getX();
|
||||
point[1] = ev.getY();
|
||||
Utilities.mapCoordInSelfToDescendant(mScrollbar, eventSource, point);
|
||||
// IF the MotionEvent is inside the thumb, container should not be pulled down.
|
||||
if (mScrollbar.shouldBlockIntercept(point[0], point[1])) {
|
||||
if (mScrollbar.shouldBlockIntercept((int) point[0], (int) point[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
@@ -150,18 +149,24 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
|
||||
|
||||
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
|
||||
int defaultIconSize = grid.iconSizePx;
|
||||
final int defaultIconSize;
|
||||
if (display == DISPLAY_WORKSPACE) {
|
||||
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
||||
defaultIconSize = grid.iconSizePx;
|
||||
} else if (display == DISPLAY_ALL_APPS) {
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
|
||||
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
|
||||
defaultIconSize = grid.allAppsIconSizePx;
|
||||
} else if (display == DISPLAY_FOLDER) {
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
|
||||
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
|
||||
defaultIconSize = grid.folderChildIconSizePx;
|
||||
} else {
|
||||
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
|
||||
}
|
||||
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
|
||||
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
|
||||
@@ -57,12 +60,14 @@ import com.android.launcher3.anim.PropertyListBuilder;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.folder.PreviewBackground;
|
||||
import com.android.launcher3.graphics.DragPreviewProvider;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.util.CellAndSpan;
|
||||
import com.android.launcher3.util.GridOccupancy;
|
||||
import com.android.launcher3.util.ParcelableSparseArray;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.Transposable;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -73,10 +78,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Stack;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
public class CellLayout extends ViewGroup {
|
||||
public class CellLayout extends ViewGroup implements Transposable {
|
||||
public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
|
||||
public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
|
||||
|
||||
@@ -182,6 +184,7 @@ public class CellLayout extends ViewGroup {
|
||||
// Related to accessible drag and drop
|
||||
private DragAndDropAccessibilityDelegate mTouchHelper;
|
||||
private boolean mUseTouchHelper = false;
|
||||
private RotationMode mRotationMode = RotationMode.NORMAL;
|
||||
|
||||
public CellLayout(Context context) {
|
||||
this(context, null);
|
||||
@@ -203,7 +206,7 @@ public class CellLayout extends ViewGroup {
|
||||
setClipToPadding(false);
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
|
||||
|
||||
mCellWidth = mCellHeight = -1;
|
||||
mFixedCellWidth = mFixedCellHeight = -1;
|
||||
@@ -317,6 +320,24 @@ public class CellLayout extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
public void setRotationMode(RotationMode mode) {
|
||||
if (mRotationMode != mode) {
|
||||
mRotationMode = mode;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotationMode getRotationMode() {
|
||||
return mRotationMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
mRotationMode.mapRect(left, top, right, bottom, mTempRect);
|
||||
super.setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Always attempt to dispatch hover events to accessibility first.
|
||||
@@ -339,6 +360,10 @@ public class CellLayout extends ViewGroup {
|
||||
mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
|
||||
}
|
||||
|
||||
public boolean isHardwareLayerEnabled() {
|
||||
return mShortcutsAndWidgets.getLayerType() == LAYER_TYPE_HARDWARE;
|
||||
}
|
||||
|
||||
public void setCellDimensions(int width, int height) {
|
||||
mFixedCellWidth = mCellWidth = width;
|
||||
mFixedCellHeight = mCellHeight = height;
|
||||
@@ -745,6 +770,14 @@ public class CellLayout extends ViewGroup {
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
|
||||
int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
|
||||
|
||||
mShortcutsAndWidgets.setRotation(mRotationMode.surfaceRotation);
|
||||
if (mRotationMode.isTransposed) {
|
||||
int tmp = childWidthSize;
|
||||
childWidthSize = childHeightSize;
|
||||
childHeightSize = tmp;
|
||||
}
|
||||
|
||||
if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
|
||||
int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX);
|
||||
int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY);
|
||||
@@ -787,7 +820,6 @@ public class CellLayout extends ViewGroup {
|
||||
int top = getPaddingTop();
|
||||
int bottom = b - t - getPaddingBottom();
|
||||
|
||||
mShortcutsAndWidgets.layout(left, top, right, bottom);
|
||||
// Expand the background drawing bounds by the padding baked into the background drawable
|
||||
mBackground.getPadding(mTempRect);
|
||||
mBackground.setBounds(
|
||||
@@ -795,6 +827,16 @@ public class CellLayout extends ViewGroup {
|
||||
top - mTempRect.top - getPaddingTop(),
|
||||
right + mTempRect.right + getPaddingRight(),
|
||||
bottom + mTempRect.bottom + getPaddingBottom());
|
||||
|
||||
if (mRotationMode.isTransposed) {
|
||||
int halfW = mShortcutsAndWidgets.getMeasuredWidth() / 2;
|
||||
int halfH = mShortcutsAndWidgets.getMeasuredHeight() / 2;
|
||||
int cX = (left + right) / 2;
|
||||
int cY = (top + bottom) / 2;
|
||||
mShortcutsAndWidgets.layout(cX - halfW, cY - halfH, cX + halfW, cY + halfH);
|
||||
} else {
|
||||
mShortcutsAndWidgets.layout(left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -929,7 +971,7 @@ public class CellLayout extends ViewGroup {
|
||||
if (resize) {
|
||||
cellToRect(cellX, cellY, spanX, spanY, r);
|
||||
if (v instanceof LauncherAppWidgetHostView) {
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
|
||||
Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -33,20 +33,12 @@ 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) {
|
||||
@@ -81,21 +73,11 @@ 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 @ " + android.util.Log.getStackTraceString(
|
||||
new Throwable()));
|
||||
}
|
||||
mView.removeCallbacks(mPendingCheckForLongPress);
|
||||
mPendingCheckForLongPress = null;
|
||||
}
|
||||
|
||||
@@ -419,6 +419,10 @@ public class DeviceProfile {
|
||||
updateWorkspacePadding();
|
||||
}
|
||||
|
||||
/**
|
||||
* The current device insets. This is generally same as the insets being dispatched to
|
||||
* {@link Insettable} elements, but can differ if the element is using a different profile.
|
||||
*/
|
||||
public Rect getInsets() {
|
||||
return mInsets;
|
||||
}
|
||||
@@ -582,45 +586,6 @@ public class DeviceProfile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an item's location on the home screen. This is useful if the home screen
|
||||
* is animating, otherwise use {@link View#getLocationOnScreen(int[])}.
|
||||
* @param pageDiff The page difference relative to the current page.
|
||||
*/
|
||||
public void getItemLocation(int cellX, int cellY, int spanX, int spanY, int container,
|
||||
int pageDiff, Rect outBounds) {
|
||||
outBounds.setEmpty();
|
||||
if (container == CONTAINER_HOTSEAT) {
|
||||
final int actualHotseatCellHeight;
|
||||
if (isVerticalBarLayout()) {
|
||||
actualHotseatCellHeight = availableHeightPx / inv.numRows;
|
||||
if (mIsSeascape) {
|
||||
outBounds.left = mHotseatPadding.left;
|
||||
} else {
|
||||
outBounds.left = availableWidthPx - hotseatBarSizePx + mHotseatPadding.left;
|
||||
}
|
||||
outBounds.right = outBounds.left + iconSizePx;
|
||||
outBounds.top = mHotseatPadding.top
|
||||
+ actualHotseatCellHeight * (inv.numRows - cellX - 1);
|
||||
outBounds.bottom = outBounds.top + actualHotseatCellHeight;
|
||||
} else {
|
||||
actualHotseatCellHeight = hotseatBarSizePx - hotseatBarBottomPaddingPx
|
||||
- hotseatBarTopPaddingPx;
|
||||
outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
|
||||
+ (cellX * getCellSize().x);
|
||||
outBounds.right = outBounds.left + getCellSize().x;
|
||||
outBounds.top = mInsets.top + availableHeightPx - hotseatBarSizePx;
|
||||
outBounds.bottom = outBounds.top + actualHotseatCellHeight;
|
||||
}
|
||||
} else {
|
||||
outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
|
||||
+ (cellX * getCellSize().x) + (pageDiff * availableWidthPx);
|
||||
outBounds.right = outBounds.left + (getCellSize().x * spanX);
|
||||
outBounds.top = mInsets.top + workspacePadding.top + (cellY * getCellSize().y);
|
||||
outBounds.bottom = outBounds.top + (getCellSize().y * spanY);
|
||||
}
|
||||
}
|
||||
|
||||
private static Context getContext(Context c, int orientation) {
|
||||
Configuration context = new Configuration(c.getResources().getConfiguration());
|
||||
context.orientation = orientation;
|
||||
|
||||
@@ -204,7 +204,7 @@ public class DropTargetBar extends FrameLayout
|
||||
return visibleCount;
|
||||
}
|
||||
|
||||
private void animateToVisibility(boolean isVisible) {
|
||||
public void animateToVisibility(boolean isVisible) {
|
||||
if (mVisible != isVisible) {
|
||||
mVisible = isVisible;
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.views.Transposable;
|
||||
|
||||
public class Hotseat extends CellLayout implements LogContainerProvider, Insettable {
|
||||
public class Hotseat extends CellLayout implements LogContainerProvider, Insettable, Transposable {
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mHasVerticalHotseat;
|
||||
@@ -77,7 +79,8 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
|
||||
insets = grid.getInsets();
|
||||
|
||||
if (grid.isVerticalBarLayout()) {
|
||||
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
@@ -105,4 +108,9 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta
|
||||
// Don't let if follow through to workspace
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotationMode getRotationMode() {
|
||||
return Launcher.getLauncher(getContext()).getRotationMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -71,6 +72,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Toast;
|
||||
@@ -93,6 +95,7 @@ import com.android.launcher3.dragndrop.DragView;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.folder.FolderIconPreviewVerifier;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.keyboard.CustomActionsPopup;
|
||||
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
||||
@@ -272,6 +275,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
private float mCurrentAssistantVisibility = 0f;
|
||||
|
||||
private DeviceProfile mStableDeviceProfile;
|
||||
private RotationMode mRotationMode = RotationMode.NORMAL;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
RaceConditionTracker.onEvent(ON_CREATE_EVT, ENTER);
|
||||
@@ -390,6 +396,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
|
||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||
lp.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
|
||||
getWindow().setAttributes(lp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -418,6 +430,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
@Override
|
||||
protected void reapplyUi() {
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
|
||||
mRotationMode = mStableDeviceProfile == null ? RotationMode.NORMAL :
|
||||
(mDeviceProfile.isSeascape() ? RotationMode.SEASCAPE : RotationMode.LANDSCAPE);
|
||||
}
|
||||
getRootView().dispatchInsets();
|
||||
getStateManager().reapplyState(true /* cancelCurrentAnimation */);
|
||||
}
|
||||
@@ -469,8 +485,41 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
display.getSize(mwSize);
|
||||
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
|
||||
}
|
||||
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get() && mDeviceProfile.isVerticalBarLayout()
|
||||
&& !mDeviceProfile.isMultiWindowMode) {
|
||||
mStableDeviceProfile = mDeviceProfile.inv.portraitProfile;
|
||||
mRotationMode = mDeviceProfile.isSeascape()
|
||||
? RotationMode.SEASCAPE : RotationMode.LANDSCAPE;
|
||||
} else {
|
||||
mStableDeviceProfile = null;
|
||||
mRotationMode = RotationMode.NORMAL;
|
||||
}
|
||||
|
||||
onDeviceProfileInitiated();
|
||||
mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout(), true);
|
||||
mModelWriter = mModel.getWriter(getWallpaperDeviceProfile().isVerticalBarLayout(), true);
|
||||
}
|
||||
|
||||
public void updateInsets(Rect insets) {
|
||||
mDeviceProfile.updateInsets(insets);
|
||||
if (mStableDeviceProfile != null) {
|
||||
mStableDeviceProfile.updateInsets(insets);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotationMode getRotationMode() {
|
||||
return mRotationMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device profile to be used by UI elements which are shown directly on top of the wallpaper
|
||||
* and whose presentation is tied to the wallpaper (and physical device) and not the activity
|
||||
* configuration.
|
||||
*/
|
||||
@Override
|
||||
public DeviceProfile getWallpaperDeviceProfile() {
|
||||
return mStableDeviceProfile == null ? mDeviceProfile : mStableDeviceProfile;
|
||||
}
|
||||
|
||||
public RotationHelper getRotationHelper() {
|
||||
@@ -879,7 +928,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
super.onPause();
|
||||
mDragController.cancelDrag();
|
||||
mDragController.resetLastGestureUpTime();
|
||||
|
||||
mDropTargetBar.animateToVisibility(false);
|
||||
if (mLauncherCallbacks != null) {
|
||||
mLauncherCallbacks.onPause();
|
||||
}
|
||||
@@ -1812,7 +1861,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mAppWidgetHost.clearViews();
|
||||
|
||||
if (mHotseat != null) {
|
||||
mHotseat.resetLayout(mDeviceProfile.isVerticalBarLayout());
|
||||
mHotseat.resetLayout(getWallpaperDeviceProfile().isVerticalBarLayout());
|
||||
}
|
||||
TraceHelper.endSection("startBinding");
|
||||
}
|
||||
|
||||
@@ -213,7 +213,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (mLock) {
|
||||
Preconditions.assertUIThread();
|
||||
mCallbacks = new WeakReference<>(callbacks);
|
||||
android.util.Log.d("b/131170582", "mCallbacks = " + mCallbacks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +330,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
// Stop any existing loaders first, so they don't set mModelLoaded to true later
|
||||
stopLoader();
|
||||
mModelLoaded = false;
|
||||
android.util.Log.d("b/131170582", "1 mModelLoaded = " + mModelLoaded);
|
||||
}
|
||||
|
||||
// Start the loader if launcher is already running, otherwise the loader will run,
|
||||
@@ -392,7 +390,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (mLock) {
|
||||
LoaderTask oldTask = mLoaderTask;
|
||||
mLoaderTask = null;
|
||||
android.util.Log.d("b/131170582", "1 mLoaderTask = " + mLoaderTask);
|
||||
if (oldTask != null) {
|
||||
oldTask.stopLocked();
|
||||
}
|
||||
@@ -403,7 +400,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (mLock) {
|
||||
stopLoader();
|
||||
mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
|
||||
android.util.Log.d("b/131170582", "2 mLoaderTask = " + mLoaderTask);
|
||||
runOnWorkerThread(mLoaderTask);
|
||||
}
|
||||
}
|
||||
@@ -448,7 +444,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
mTask = task;
|
||||
mIsLoaderTaskRunning = true;
|
||||
mModelLoaded = false;
|
||||
android.util.Log.d("b/131170582", "2 mModelLoaded = " + mModelLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +451,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (mLock) {
|
||||
// Everything loaded bind the data.
|
||||
mModelLoaded = true;
|
||||
android.util.Log.d("b/131170582", "3 mModelLoaded = " + mModelLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +460,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
// If we are still the last one to be scheduled, remove ourselves.
|
||||
if (mLoaderTask == mTask) {
|
||||
mLoaderTask = null;
|
||||
android.util.Log.d("b/131170582", "3 mLoaderTask = " + mLoaderTask);
|
||||
}
|
||||
mIsLoaderTaskRunning = false;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,10 @@ import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.WindowInsets;
|
||||
@@ -31,9 +28,6 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private final Rect mConsumedInsets = new Rect();
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private final RectF mTouchExcludeRegion = new RectF();
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
@@ -87,7 +81,7 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
UI_STATE_ROOT_VIEW, drawInsetBar ? FLAG_DARK_NAV : 0);
|
||||
|
||||
// Update device profile before notifying th children.
|
||||
mLauncher.getDeviceProfile().updateInsets(insets);
|
||||
mLauncher.updateInsets(insets);
|
||||
boolean resetState = !insets.equals(mInsets);
|
||||
setInsets(insets);
|
||||
|
||||
@@ -120,7 +114,7 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
}
|
||||
|
||||
public void dispatchInsets() {
|
||||
mLauncher.getDeviceProfile().updateInsets(mInsets);
|
||||
mLauncher.updateInsets(mInsets);
|
||||
super.setInsets(mInsets);
|
||||
}
|
||||
|
||||
@@ -164,29 +158,10 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
|
||||
@Override
|
||||
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
Insets gestureInsets = insets.getMandatorySystemGestureInsets();
|
||||
mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
|
||||
gestureInsets.right, gestureInsets.bottom);
|
||||
}
|
||||
mLauncher.getDragLayer().updateTouchExcludeRegion(insets);
|
||||
return super.dispatchApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
float x = ev.getX();
|
||||
float y = ev.getY();
|
||||
if (y < mTouchExcludeRegion.top
|
||||
|| x < mTouchExcludeRegion.left
|
||||
|| x > (getWidth() - mTouchExcludeRegion.right)
|
||||
|| y > (getHeight() - mTouchExcludeRegion.bottom)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
@@ -211,14 +186,4 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
|
||||
void onWindowVisibilityChanged(int visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
super.requestLayout();
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"requestLayout @ " + android.util.Log.getStackTraceString(
|
||||
new Throwable()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1088,10 +1088,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
super.onTouchEvent(ev);
|
||||
|
||||
// Skip touch handling if there are no pages to swipe
|
||||
if (getChildCount() <= 0) return super.onTouchEvent(ev);
|
||||
if (getChildCount() <= 0) return false;
|
||||
|
||||
acquireVelocityTrackerAndAddMovement(ev);
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
|
||||
public void setupLp(View child) {
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
|
||||
profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
} else {
|
||||
@@ -108,12 +108,12 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
|
||||
|
||||
public int getCellContentHeight() {
|
||||
return Math.min(getMeasuredHeight(),
|
||||
mActivity.getDeviceProfile().getCellHeight(mContainerType));
|
||||
mActivity.getWallpaperDeviceProfile().getCellHeight(mContainerType));
|
||||
}
|
||||
|
||||
public void measureChild(View child) {
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
|
||||
final DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
final DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
|
||||
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
|
||||
|
||||
@@ -63,9 +63,4 @@ public final class TestProtocol {
|
||||
"all-apps-to-overview-swipe-height";
|
||||
public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
|
||||
"home-to-all-apps-swipe-height";
|
||||
|
||||
public static boolean sDebugTracing = false;
|
||||
public static final String NO_DRAG_TAG = "b/129434166";
|
||||
public static final String REQUEST_ENABLE_DRAG_LOGGING = "enable-drag-logging";
|
||||
public static final String REQUEST_DISABLE_DRAG_LOGGING = "disable-drag-logging";
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.WallpaperManager;
|
||||
@@ -63,13 +60,12 @@ import android.view.animation.Interpolator;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.views.Transposable;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
|
||||
import java.io.Closeable;
|
||||
@@ -97,7 +93,6 @@ public final class Utilities {
|
||||
|
||||
private static final int[] sLoc0 = new int[2];
|
||||
private static final int[] sLoc1 = new int[2];
|
||||
private static final float[] sPoint = new float[2];
|
||||
private static final Matrix sMatrix = new Matrix();
|
||||
private static final Matrix sInverseMatrix = new Matrix();
|
||||
|
||||
@@ -143,7 +138,7 @@ public final class Utilities {
|
||||
*/
|
||||
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
|
||||
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
|
||||
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
|
||||
|
||||
public static boolean IS_RUNNING_IN_TEST_HARNESS =
|
||||
ActivityManager.isRunningInTestHarness();
|
||||
@@ -170,37 +165,60 @@ public final class Utilities {
|
||||
* assumption fails, we will need to return a pair of scale factors.
|
||||
*/
|
||||
public static float getDescendantCoordRelativeToAncestor(
|
||||
View descendant, View ancestor, int[] coord, boolean includeRootScroll) {
|
||||
sPoint[0] = coord[0];
|
||||
sPoint[1] = coord[1];
|
||||
View descendant, View ancestor, float[] coord, boolean includeRootScroll) {
|
||||
return getDescendantCoordRelativeToAncestor(descendant, ancestor, coord, includeRootScroll,
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
|
||||
* coordinates.
|
||||
*
|
||||
* @param descendant The descendant to which the passed coordinate is relative.
|
||||
* @param ancestor The root view to make the coordinates relative to.
|
||||
* @param coord The coordinate that we want mapped.
|
||||
* @param includeRootScroll Whether or not to account for the scroll of the descendant:
|
||||
* sometimes this is relevant as in a child's coordinates within the descendant.
|
||||
* @param ignoreTransform If true, view transform is ignored
|
||||
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
|
||||
* this scale factor is assumed to be equal in X and Y, and so if at any point this
|
||||
* assumption fails, we will need to return a pair of scale factors.
|
||||
*/
|
||||
public static float getDescendantCoordRelativeToAncestor(View descendant, View ancestor,
|
||||
float[] coord, boolean includeRootScroll, boolean ignoreTransform) {
|
||||
float scale = 1.0f;
|
||||
View v = descendant;
|
||||
while(v != ancestor && v != null) {
|
||||
// For TextViews, scroll has a meaning which relates to the text position
|
||||
// which is very strange... ignore the scroll.
|
||||
if (v != descendant || includeRootScroll) {
|
||||
sPoint[0] -= v.getScrollX();
|
||||
sPoint[1] -= v.getScrollY();
|
||||
offsetPoints(coord, -v.getScrollX(), -v.getScrollY());
|
||||
}
|
||||
|
||||
v.getMatrix().mapPoints(sPoint);
|
||||
sPoint[0] += v.getLeft();
|
||||
sPoint[1] += v.getTop();
|
||||
if (ignoreTransform) {
|
||||
if (v instanceof Transposable) {
|
||||
RotationMode m = ((Transposable) v).getRotationMode();
|
||||
if (m.isTransposed) {
|
||||
sMatrix.setRotate(m.surfaceRotation, v.getPivotX(), v.getPivotY());
|
||||
sMatrix.mapPoints(coord);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v.getMatrix().mapPoints(coord);
|
||||
}
|
||||
offsetPoints(coord, v.getLeft(), v.getTop());
|
||||
scale *= v.getScaleX();
|
||||
|
||||
v = (View) v.getParent();
|
||||
}
|
||||
|
||||
coord[0] = Math.round(sPoint[0]);
|
||||
coord[1] = Math.round(sPoint[1]);
|
||||
return scale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, int[], boolean)}.
|
||||
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
|
||||
*/
|
||||
public static void mapCoordInSelfToDescendant(View descendant, View root, int[] coord) {
|
||||
public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
|
||||
sMatrix.reset();
|
||||
View v = descendant;
|
||||
while(v != root) {
|
||||
@@ -211,12 +229,23 @@ public final class Utilities {
|
||||
}
|
||||
sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
|
||||
sMatrix.invert(sInverseMatrix);
|
||||
sInverseMatrix.mapPoints(coord);
|
||||
}
|
||||
|
||||
sPoint[0] = coord[0];
|
||||
sPoint[1] = coord[1];
|
||||
sInverseMatrix.mapPoints(sPoint);
|
||||
coord[0] = Math.round(sPoint[0]);
|
||||
coord[1] = Math.round(sPoint[1]);
|
||||
/**
|
||||
* Sets {@param out} to be same as {@param in} by rounding individual values
|
||||
*/
|
||||
public static void roundArray(float[] in, int[] out) {
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
out[i] = Math.round(in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void offsetPoints(float[] points, float offsetX, float offsetY) {
|
||||
for (int i = 0; i < points.length; i += 2) {
|
||||
points[i] += offsetX;
|
||||
points[i + 1] += offsetY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -569,53 +598,6 @@ public final class Utilities {
|
||||
return String.format(Locale.ENGLISH, "%d,%d", x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location bounds of a view.
|
||||
* - For DeepShortcutView, we return the bounds of the icon view.
|
||||
* - For BubbleTextView, we return the icon bounds.
|
||||
*/
|
||||
public static void getLocationBoundsForView(Launcher launcher, View v, Rect outRect) {
|
||||
final DragLayer dragLayer = launcher.getDragLayer();
|
||||
final boolean isBubbleTextView = v instanceof BubbleTextView;
|
||||
final boolean isFolderIcon = v instanceof FolderIcon;
|
||||
final Rect rect = new Rect();
|
||||
|
||||
// Deep shortcut views have their icon drawn in a separate view.
|
||||
final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
|
||||
if (v instanceof DeepShortcutView) {
|
||||
dragLayer.getDescendantRectRelativeToSelf(((DeepShortcutView) v).getIconView(), rect);
|
||||
} else if (fromDeepShortcutView) {
|
||||
DeepShortcutView view = (DeepShortcutView) v.getParent();
|
||||
dragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect);
|
||||
} else if ((isBubbleTextView || isFolderIcon) && v.getTag() instanceof ItemInfo
|
||||
&& (((ItemInfo) v.getTag()).container == CONTAINER_DESKTOP
|
||||
|| ((ItemInfo) v.getTag()).container == CONTAINER_HOTSEAT)) {
|
||||
CellLayout pageViewIsOn = ((CellLayout) v.getParent().getParent());
|
||||
int pageNum = launcher.getWorkspace().indexOfChild(pageViewIsOn);
|
||||
|
||||
DeviceProfile dp = launcher.getDeviceProfile();
|
||||
ItemInfo info = ((ItemInfo) v.getTag());
|
||||
dp.getItemLocation(info.cellX, info.cellY, info.spanX, info.spanY,
|
||||
info.container, pageNum - launcher.getCurrentWorkspaceScreen(), rect);
|
||||
} else {
|
||||
dragLayer.getDescendantRectRelativeToSelf(v, rect);
|
||||
}
|
||||
int viewLocationLeft = rect.left;
|
||||
int viewLocationTop = rect.top;
|
||||
|
||||
if (isBubbleTextView && !fromDeepShortcutView) {
|
||||
((BubbleTextView) v).getIconBounds(rect);
|
||||
} else if (isFolderIcon) {
|
||||
((FolderIcon) v).getPreviewBounds(rect);
|
||||
} else {
|
||||
rect.set(0, 0, rect.width(), rect.height());
|
||||
}
|
||||
viewLocationLeft += rect.left;
|
||||
viewLocationTop += rect.top;
|
||||
outRect.set(viewLocationLeft, viewLocationTop, viewLocationLeft + rect.width(),
|
||||
viewLocationTop + rect.height());
|
||||
}
|
||||
|
||||
public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) {
|
||||
try {
|
||||
context.unregisterReceiver(receiver);
|
||||
|
||||
@@ -82,6 +82,7 @@ import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.folder.PreviewBackground;
|
||||
import com.android.launcher3.graphics.DragPreviewProvider;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
|
||||
@@ -175,7 +176,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
@Thunk final Launcher mLauncher;
|
||||
@Thunk DragController mDragController;
|
||||
|
||||
private final Rect mTempRect = new Rect();
|
||||
private final int[] mTempXY = new int[2];
|
||||
private final float[] mTempFXY = new float[2];
|
||||
@Thunk float[] mDragViewVisualCenter = new float[2];
|
||||
private final float[] mTempTouchCoordinates = new float[2];
|
||||
|
||||
@@ -285,18 +288,23 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets.set(insets);
|
||||
|
||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||
mMaxDistanceForFolderCreation = grid.isTablet
|
||||
? 0.75f * grid.iconSizePx
|
||||
: 0.55f * grid.iconSizePx;
|
||||
DeviceProfile stableGrid = mLauncher.getWallpaperDeviceProfile();
|
||||
|
||||
mMaxDistanceForFolderCreation = stableGrid.isTablet
|
||||
? 0.75f * stableGrid.iconSizePx
|
||||
: 0.55f * stableGrid.iconSizePx;
|
||||
mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
|
||||
|
||||
Rect padding = grid.workspacePadding;
|
||||
setPadding(padding.left, padding.top, padding.right, padding.bottom);
|
||||
Rect padding = stableGrid.workspacePadding;
|
||||
|
||||
if (grid.shouldFadeAdjacentWorkspaceScreens()) {
|
||||
RotationMode rotationMode = mLauncher.getRotationMode();
|
||||
|
||||
rotationMode.mapRect(padding, mTempRect);
|
||||
setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
|
||||
rotationMode.mapRect(insets, mInsets);
|
||||
|
||||
if (mWorkspaceFadeInAdjacentScreens) {
|
||||
// In landscape mode the page spacing is set to the default.
|
||||
setPageSpacing(grid.edgeMarginPx);
|
||||
} else {
|
||||
@@ -306,11 +314,13 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
setPageSpacing(Math.max(grid.edgeMarginPx, padding.left + 1));
|
||||
}
|
||||
|
||||
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
|
||||
int paddingBottom = grid.cellLayoutBottomPaddingPx;
|
||||
|
||||
int paddingLeftRight = stableGrid.cellLayoutPaddingLeftRightPx;
|
||||
int paddingBottom = stableGrid.cellLayoutBottomPaddingPx;
|
||||
for (int i = mWorkspaceScreens.size() - 1; i >= 0; i--) {
|
||||
mWorkspaceScreens.valueAt(i)
|
||||
.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
|
||||
CellLayout page = mWorkspaceScreens.valueAt(i);
|
||||
page.setRotationMode(rotationMode);
|
||||
page.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +340,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
float scale = 1;
|
||||
if (isWidget) {
|
||||
DeviceProfile profile = mLauncher.getDeviceProfile();
|
||||
DeviceProfile profile = mLauncher.getWallpaperDeviceProfile();
|
||||
scale = Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
}
|
||||
size[0] = r.width();
|
||||
@@ -550,8 +560,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
// created CellLayout.
|
||||
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.workspace_screen, this, false /* attachToRoot */);
|
||||
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
|
||||
int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
|
||||
DeviceProfile grid = mLauncher.getWallpaperDeviceProfile();
|
||||
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
|
||||
int paddingBottom = grid.cellLayoutBottomPaddingPx;
|
||||
newScreen.setRotationMode(mLauncher.getRotationMode());
|
||||
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
|
||||
|
||||
mWorkspaceScreens.put(screenId, newScreen);
|
||||
@@ -1440,10 +1452,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
|
||||
DragPreviewProvider previewProvider, DragOptions dragOptions) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"beginDragShared");
|
||||
}
|
||||
float iconScale = 1f;
|
||||
if (child instanceof BubbleTextView) {
|
||||
Drawable icon = ((BubbleTextView) child).getIcon();
|
||||
@@ -1934,18 +1942,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
if (child == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
|
||||
|
||||
// Use the absolute left instead of the child left, as we want the visible area
|
||||
// irrespective of the visible child. Since the view can only scroll horizontally, the
|
||||
// top position is not affected.
|
||||
mTempXY[0] = getPaddingLeft() + boundingLayout.getLeft();
|
||||
mTempXY[1] = child.getTop() + boundingLayout.getTop();
|
||||
|
||||
float scale = mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY);
|
||||
outArea.set(mTempXY[0], mTempXY[1],
|
||||
(int) (mTempXY[0] + scale * boundingLayout.getMeasuredWidth()),
|
||||
(int) (mTempXY[1] + scale * boundingLayout.getMeasuredHeight()));
|
||||
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, outArea);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2098,14 +2097,14 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
|
||||
boolean isPointInSelfOverHotseat(int x, int y) {
|
||||
mTempXY[0] = x;
|
||||
mTempXY[1] = y;
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
|
||||
mTempFXY[0] = x;
|
||||
mTempFXY[1] = y;
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempFXY, true);
|
||||
View hotseat = mLauncher.getHotseat();
|
||||
return mTempXY[0] >= hotseat.getLeft() &&
|
||||
mTempXY[0] <= hotseat.getRight() &&
|
||||
mTempXY[1] >= hotseat.getTop() &&
|
||||
mTempXY[1] <= hotseat.getBottom();
|
||||
return mTempFXY[0] >= hotseat.getLeft() &&
|
||||
mTempFXY[0] <= hotseat.getRight() &&
|
||||
mTempFXY[1] >= hotseat.getTop() &&
|
||||
mTempFXY[1] <= hotseat.getBottom();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2115,13 +2114,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
*/
|
||||
private void mapPointFromDropLayout(CellLayout layout, float[] xy) {
|
||||
if (mLauncher.isHotseatLayout(layout)) {
|
||||
mTempXY[0] = (int) xy[0];
|
||||
mTempXY[1] = (int) xy[1];
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
|
||||
mLauncher.getDragLayer().mapCoordInSelfToDescendant(layout, mTempXY);
|
||||
|
||||
xy[0] = mTempXY[0];
|
||||
xy[1] = mTempXY[1];
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, xy, true);
|
||||
mLauncher.getDragLayer().mapCoordInSelfToDescendant(layout, xy);
|
||||
} else {
|
||||
mapPointFromSelfToChild(layout, xy);
|
||||
}
|
||||
@@ -2612,13 +2606,14 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
DeviceProfile profile = mLauncher.getDeviceProfile();
|
||||
Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
}
|
||||
loc[0] = r.left;
|
||||
loc[1] = r.top;
|
||||
|
||||
mTempFXY[0] = r.left;
|
||||
mTempFXY[1] = r.top;
|
||||
setFinalTransitionTransform();
|
||||
float cellLayoutScale =
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, mTempFXY, true);
|
||||
resetTransitionTransform();
|
||||
Utilities.roundArray(mTempFXY, loc);
|
||||
|
||||
if (scale) {
|
||||
float dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
|
||||
@@ -2911,14 +2906,11 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
&& info.user.equals(user);
|
||||
final Workspace.ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
|
||||
packageAndUser.evaluate(info, view) && info.itemType == ITEM_TYPE_APPLICATION;
|
||||
final Workspace.ItemOperator packageAndUserAndShortcut = (ItemInfo info, View view) ->
|
||||
packageAndUser.evaluate(info, view) && (info.itemType == ITEM_TYPE_SHORTCUT
|
||||
|| info.itemType == ITEM_TYPE_DEEP_SHORTCUT);
|
||||
final Workspace.ItemOperator packageAndUserInFolder = (info, view) -> {
|
||||
final Workspace.ItemOperator packageAndUserAndAppInFolder = (info, view) -> {
|
||||
if (info instanceof FolderInfo) {
|
||||
FolderInfo folderInfo = (FolderInfo) info;
|
||||
for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
|
||||
if (packageAndUser.evaluate(shortcutInfo, view)) {
|
||||
if (packageAndUserAndApp.evaluate(shortcutInfo, view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2926,15 +2918,15 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
return false;
|
||||
};
|
||||
|
||||
// Order: App icons, shortcuts, app/shortcut in folder. Items in hotseat get returned first.
|
||||
// Order: App icons, app in folder. Items in hotseat get returned first.
|
||||
if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
|
||||
return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
|
||||
packageAndUserAndApp, packageAndUserAndShortcut, packageAndUserInFolder);
|
||||
packageAndUserAndApp, packageAndUserAndAppInFolder);
|
||||
} else {
|
||||
// Do not use Folder as a criteria, since it'll cause a crash when trying to draw
|
||||
// FolderAdaptiveIcon as the background.
|
||||
return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
|
||||
packageAndUserAndApp, packageAndUserAndShortcut);
|
||||
packageAndUserAndApp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,14 +93,16 @@ public class WorkspaceStateTransitionAnimation {
|
||||
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
|
||||
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
|
||||
|
||||
// Set the hotseat's pivot point to match the workspace's, so that it scales together.
|
||||
DragLayer dragLayer = mLauncher.getDragLayer();
|
||||
int[] workspacePivot = new int[]{(int) mWorkspace.getPivotX(),
|
||||
(int) mWorkspace.getPivotY()};
|
||||
dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
|
||||
dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
|
||||
hotseat.setPivotX(workspacePivot[0]);
|
||||
hotseat.setPivotY(workspacePivot[1]);
|
||||
if (!hotseat.getRotationMode().isTransposed) {
|
||||
// Set the hotseat's pivot point to match the workspace's, so that it scales together.
|
||||
DragLayer dragLayer = mLauncher.getDragLayer();
|
||||
float[] workspacePivot =
|
||||
new float[]{ mWorkspace.getPivotX(), mWorkspace.getPivotY() };
|
||||
dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
|
||||
dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
|
||||
hotseat.setPivotX(workspacePivot[0]);
|
||||
hotseat.setPivotY(workspacePivot[1]);
|
||||
}
|
||||
float hotseatScale = hotseatScaleAndTranslation.scale;
|
||||
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, scaleInterpolator);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ public class FlingSpringAnim {
|
||||
private static final float SPRING_DAMPING = SpringForce.DAMPING_RATIO_LOW_BOUNCY;
|
||||
|
||||
private final FlingAnimation mFlingAnim;
|
||||
private SpringAnimation mSpringAnim;
|
||||
|
||||
public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
|
||||
float targetPosition, float startVelocity, OnAnimationEndListener onEndListener) {
|
||||
@@ -44,17 +45,24 @@ public class FlingSpringAnim {
|
||||
.setMinValue(Math.min(startPosition, targetPosition))
|
||||
.setMaxValue(Math.max(startPosition, targetPosition));
|
||||
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
|
||||
SpringAnimation springAnim = new SpringAnimation(object, property)
|
||||
mSpringAnim = new SpringAnimation(object, property)
|
||||
.setStartVelocity(velocity)
|
||||
.setSpring(new SpringForce(targetPosition)
|
||||
.setStiffness(SPRING_STIFFNESS)
|
||||
.setDampingRatio(SPRING_DAMPING));
|
||||
springAnim.addEndListener(onEndListener);
|
||||
springAnim.start();
|
||||
mSpringAnim.addEndListener(onEndListener);
|
||||
mSpringAnim.start();
|
||||
}));
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mFlingAnim.start();
|
||||
}
|
||||
|
||||
public void end() {
|
||||
mFlingAnim.cancel();
|
||||
if (mSpringAnim.canSkipToEnd()) {
|
||||
mSpringAnim.skipToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ abstract class BaseFlags {
|
||||
"ENABLE_HINTS_IN_OVERVIEW", false,
|
||||
"Show chip hints and gleams on the overview screen");
|
||||
|
||||
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
|
||||
"FAKE_LANDSCAPE_UI", false,
|
||||
"Rotate launcher UI instead of using transposed layout");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
// Avoid the disk read for user builds
|
||||
if (Utilities.IS_DEBUG_DEVICE) {
|
||||
|
||||
@@ -219,9 +219,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
}
|
||||
|
||||
private void callOnDragStart() {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG, "callOnDragStart");
|
||||
}
|
||||
if (mOptions.preDragCondition != null) {
|
||||
mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/);
|
||||
}
|
||||
@@ -475,9 +472,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
}
|
||||
|
||||
private void handleMoveEvent(int x, int y) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG, "handleMoveEvent1");
|
||||
}
|
||||
mDragObject.dragView.move(x, y);
|
||||
|
||||
// Drop on someone?
|
||||
@@ -494,10 +488,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
if (mIsInPreDrag && mOptions.preDragCondition != null
|
||||
&& mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"handleMoveEvent2");
|
||||
}
|
||||
callOnDragStart();
|
||||
}
|
||||
}
|
||||
@@ -535,10 +525,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
* Call this from a drag source view.
|
||||
*/
|
||||
public boolean onControllerTouchEvent(MotionEvent ev) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onControllerTouchEvent1");
|
||||
}
|
||||
if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
|
||||
return false;
|
||||
}
|
||||
@@ -559,10 +545,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
break;
|
||||
}
|
||||
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onControllerTouchEvent2");
|
||||
}
|
||||
return mDragDriver.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,18 +45,10 @@ public abstract class DragDriver {
|
||||
public void onDragViewAnimationEnd() { }
|
||||
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onTouchEvent " + ev);
|
||||
}
|
||||
final int action = ev.getAction();
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onTouchEvent MOVE");
|
||||
}
|
||||
mEventListener.onDriverDragMove(ev.getX(), ev.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import static android.view.View.MeasureSpec.getMode;
|
||||
import static android.view.View.MeasureSpec.getSize;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -29,12 +33,14 @@ import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
@@ -42,6 +48,7 @@ import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DropTargetBar;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -52,6 +59,7 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
||||
import com.android.launcher3.uioverrides.UiFactory;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.views.Transposable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -126,10 +134,6 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
protected boolean findActiveController(MotionEvent ev) {
|
||||
if (mActivity.getStateManager().getState().disableInteraction) {
|
||||
// You Shall Not Pass!!!
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"mActiveController = null");
|
||||
}
|
||||
mActiveController = null;
|
||||
return true;
|
||||
}
|
||||
@@ -264,10 +268,10 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
Rect r = new Rect();
|
||||
getViewRectRelativeToSelf(dragView, r);
|
||||
|
||||
int coord[] = new int[2];
|
||||
float coord[] = new float[2];
|
||||
float childScale = child.getScaleX();
|
||||
coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
|
||||
coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
|
||||
coord[0] = lp.x + (child.getMeasuredWidth() * (1 - childScale) / 2);
|
||||
coord[1] = lp.y + (child.getMeasuredHeight() * (1 - childScale) / 2);
|
||||
|
||||
// Since the child hasn't necessarily been laid out, we force the lp to be updated with
|
||||
// the correct coordinates (above) and use these to determine the final location
|
||||
@@ -275,8 +279,8 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
// We need to account for the scale of the child itself, as the above only accounts for
|
||||
// for the scale in parents.
|
||||
scale *= childScale;
|
||||
int toX = coord[0];
|
||||
int toY = coord[1];
|
||||
int toX = Math.round(coord[0]);
|
||||
int toY = Math.round(coord[1]);
|
||||
float toScale = scale;
|
||||
if (child instanceof TextView) {
|
||||
TextView tv = (TextView) child;
|
||||
@@ -555,4 +559,159 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public WorkspaceAndHotseatScrim getScrim() {
|
||||
return mScrim;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
RotationMode rotation = mActivity.getRotationMode();
|
||||
int count = getChildCount();
|
||||
|
||||
if (!rotation.isTransposed
|
||||
|| getMode(widthMeasureSpec) != EXACTLY
|
||||
|| getMode(heightMeasureSpec) != EXACTLY) {
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
child.setRotation(rotation.surfaceRotation);
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
if (!(child instanceof Transposable)) {
|
||||
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
||||
} else {
|
||||
measureChildWithMargins(child, heightMeasureSpec, 0, widthMeasureSpec, 0);
|
||||
|
||||
child.setPivotX(child.getMeasuredWidth() / 2);
|
||||
child.setPivotY(child.getMeasuredHeight() / 2);
|
||||
child.setRotation(rotation.surfaceRotation);
|
||||
}
|
||||
}
|
||||
setMeasuredDimension(getSize(widthMeasureSpec), getSize(heightMeasureSpec));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
RotationMode rotation = mActivity.getRotationMode();
|
||||
if (!rotation.isTransposed) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
final int count = getChildCount();
|
||||
|
||||
final int parentWidth = right - left;
|
||||
final int parentHeight = bottom - top;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (lp instanceof LayoutParams) {
|
||||
final LayoutParams dlp = (LayoutParams) lp;
|
||||
if (dlp.customPosition) {
|
||||
child.layout(dlp.x, dlp.y, dlp.x + dlp.width, dlp.y + dlp.height);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final int width = child.getMeasuredWidth();
|
||||
final int height = child.getMeasuredHeight();
|
||||
|
||||
int childLeft;
|
||||
int childTop;
|
||||
|
||||
int gravity = lp.gravity;
|
||||
if (gravity == -1) {
|
||||
gravity = Gravity.TOP | Gravity.START;
|
||||
}
|
||||
|
||||
final int layoutDirection = getLayoutDirection();
|
||||
|
||||
int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
|
||||
int horizontalGravity = absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
|
||||
int verticalGravity = absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK;
|
||||
|
||||
if (child instanceof Transposable) {
|
||||
if (rotation == RotationMode.SEASCAPE) {
|
||||
if (horizontalGravity == Gravity.RIGHT) {
|
||||
horizontalGravity = Gravity.LEFT;
|
||||
} else if (horizontalGravity == Gravity.LEFT) {
|
||||
horizontalGravity = Gravity.RIGHT;
|
||||
}
|
||||
|
||||
if (verticalGravity == Gravity.TOP) {
|
||||
verticalGravity = Gravity.BOTTOM;
|
||||
} else if (verticalGravity == Gravity.BOTTOM) {
|
||||
verticalGravity = Gravity.TOP;
|
||||
}
|
||||
}
|
||||
|
||||
switch (horizontalGravity) {
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
childTop = (parentHeight - height) / 2 +
|
||||
lp.topMargin - lp.bottomMargin;
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
childTop = width / 2 + lp.rightMargin - height / 2;
|
||||
break;
|
||||
case Gravity.LEFT:
|
||||
default:
|
||||
childTop = parentHeight - lp.leftMargin - width / 2 - height / 2;
|
||||
}
|
||||
|
||||
switch (verticalGravity) {
|
||||
case Gravity.CENTER_VERTICAL:
|
||||
childLeft = (parentWidth - width) / 2 +
|
||||
lp.leftMargin - lp.rightMargin;
|
||||
break;
|
||||
case Gravity.BOTTOM:
|
||||
childLeft = parentWidth - width / 2 - height / 2 - lp.bottomMargin;
|
||||
break;
|
||||
case Gravity.TOP:
|
||||
default:
|
||||
childLeft = height / 2 - width / 2 + lp.topMargin;
|
||||
}
|
||||
} else {
|
||||
switch (horizontalGravity) {
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
childLeft = (parentWidth - width) / 2 +
|
||||
lp.leftMargin - lp.rightMargin;
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
childLeft = parentWidth - width - lp.rightMargin;
|
||||
break;
|
||||
case Gravity.LEFT:
|
||||
default:
|
||||
childLeft = lp.leftMargin;
|
||||
}
|
||||
|
||||
switch (verticalGravity) {
|
||||
case Gravity.TOP:
|
||||
childTop = lp.topMargin;
|
||||
break;
|
||||
case Gravity.CENTER_VERTICAL:
|
||||
childTop = (parentHeight - height) / 2 +
|
||||
lp.topMargin - lp.bottomMargin;
|
||||
break;
|
||||
case Gravity.BOTTOM:
|
||||
childTop = parentHeight - height - lp.bottomMargin;
|
||||
break;
|
||||
default:
|
||||
childTop = lp.topMargin;
|
||||
}
|
||||
}
|
||||
|
||||
child.layout(childLeft, childTop, childLeft + width, childTop + height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
@@ -61,8 +62,10 @@ import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.OnAlarmListener;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.Workspace.ItemOperator;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
@@ -121,6 +124,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
private static final int REORDER_DELAY = 250;
|
||||
private static final int ON_EXIT_CLOSE_DELAY = 400;
|
||||
private static final Rect sTempRect = new Rect();
|
||||
private static final int MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION = 10;
|
||||
|
||||
private static String sDefaultFolderName;
|
||||
private static String sHintText;
|
||||
@@ -430,21 +434,44 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
|
||||
mCurrentAnimator.cancel();
|
||||
}
|
||||
final Workspace workspace = mLauncher.getWorkspace();
|
||||
final CellLayout currentCellLayout =
|
||||
(CellLayout) workspace.getChildAt(workspace.getCurrentPage());
|
||||
final boolean useHardware = shouldUseHardwareLayerForAnimation(currentCellLayout);
|
||||
final boolean wasHardwareAccelerated = currentCellLayout.isHardwareLayerEnabled();
|
||||
|
||||
a.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (useHardware) {
|
||||
currentCellLayout.enableHardwareLayer(true);
|
||||
}
|
||||
mState = STATE_ANIMATING;
|
||||
mCurrentAnimator = a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (useHardware) {
|
||||
currentCellLayout.enableHardwareLayer(wasHardwareAccelerated);
|
||||
}
|
||||
mCurrentAnimator = null;
|
||||
}
|
||||
});
|
||||
a.start();
|
||||
}
|
||||
|
||||
private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
|
||||
int folderCount = 0;
|
||||
final ShortcutAndWidgetContainer container = currentCellLayout.getShortcutsAndWidgets();
|
||||
for (int i = container.getChildCount() - 1; i >= 0; --i) {
|
||||
final View child = container.getChildAt(i);
|
||||
if (child instanceof AppWidgetHostView) return false;
|
||||
if (child instanceof FolderIcon) ++folderCount;
|
||||
}
|
||||
return folderCount >= MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the user folder described by the specified tag. The opening of the folder
|
||||
* is animated relative to the specified View. If the View is null, no animation
|
||||
@@ -869,7 +896,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||
|
||||
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
|
||||
DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
|
||||
DragLayer parent = mLauncher.getDragLayer();
|
||||
int width = getFolderWidth();
|
||||
int height = getFolderHeight();
|
||||
|
||||
@@ -881,8 +908,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
// We need to bound the folder to the currently visible workspace area
|
||||
if (mLauncher.getStateManager().getState().overviewUi) {
|
||||
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mLauncher.getOverviewPanel(),
|
||||
sTempRect);
|
||||
parent.getDescendantRectRelativeToSelf(mLauncher.getOverviewPanel(), sTempRect);
|
||||
} else {
|
||||
mLauncher.getWorkspace().getPageAreaRelativeToDragLayer(sTempRect);
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
"is dependent on this");
|
||||
}
|
||||
|
||||
DeviceProfile grid = launcher.getDeviceProfile();
|
||||
DeviceProfile grid = launcher.getWallpaperDeviceProfile();
|
||||
FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext())
|
||||
.inflate(resId, group, false);
|
||||
|
||||
@@ -174,7 +174,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
icon.setOnClickListener(ItemClickHandler.INSTANCE);
|
||||
icon.mInfo = folderInfo;
|
||||
icon.mLauncher = launcher;
|
||||
icon.mDotRenderer = launcher.getDeviceProfile().mDotRenderer;
|
||||
icon.mDotRenderer = grid.mDotRenderer;
|
||||
icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title));
|
||||
Folder folder = Folder.fromXml(launcher);
|
||||
folder.setDragController(launcher.getDragController());
|
||||
@@ -508,7 +508,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
public void drawDot(Canvas canvas) {
|
||||
if ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0) {
|
||||
Rect iconBounds = mDotParams.iconBounds;
|
||||
BubbleTextView.getIconBounds(this, iconBounds, mLauncher.getDeviceProfile().iconSizePx);
|
||||
BubbleTextView.getIconBounds(this, iconBounds,
|
||||
mLauncher.getWallpaperDeviceProfile().iconSizePx);
|
||||
|
||||
// If we are animating to the accepting state, animate the dot out.
|
||||
mDotParams.scale = Math.max(0, mDotScale - mBackground.getScaleProgress());
|
||||
|
||||
@@ -42,7 +42,6 @@ import android.view.View;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
/**
|
||||
@@ -135,7 +134,7 @@ public class PreviewBackground {
|
||||
mBgColor = ta.getColor(R.styleable.FolderIconPreview_android_colorPrimary, 0);
|
||||
ta.recycle();
|
||||
|
||||
DeviceProfile grid = activity.getDeviceProfile();
|
||||
DeviceProfile grid = activity.getWallpaperDeviceProfile();
|
||||
previewSize = grid.folderIconSizePx;
|
||||
|
||||
basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.graphics;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
public abstract class RotationMode {
|
||||
|
||||
public final float surfaceRotation;
|
||||
public final boolean isTransposed;
|
||||
|
||||
private RotationMode(float surfaceRotation) {
|
||||
this.surfaceRotation = surfaceRotation;
|
||||
isTransposed = surfaceRotation != 0;
|
||||
}
|
||||
|
||||
public final void mapRect(Rect rect, Rect out) {
|
||||
mapRect(rect.left, rect.top, rect.right, rect.bottom, out);
|
||||
}
|
||||
|
||||
public void mapRect(int left, int top, int right, int bottom, Rect out) {
|
||||
out.set(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public static RotationMode NORMAL = new RotationMode(0) { };
|
||||
|
||||
public static RotationMode LANDSCAPE = new RotationMode(-90) {
|
||||
@Override
|
||||
public void mapRect(int left, int top, int right, int bottom, Rect out) {
|
||||
out.left = top;
|
||||
out.top = right;
|
||||
out.right = bottom;
|
||||
out.bottom = left;
|
||||
}
|
||||
};
|
||||
|
||||
public static RotationMode SEASCAPE = new RotationMode(90) {
|
||||
@Override
|
||||
public void mapRect(int left, int top, int right, int bottom, Rect out) {
|
||||
out.left = bottom;
|
||||
out.top = left;
|
||||
out.right = top;
|
||||
out.bottom = right;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFI
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.LayoutTransition;
|
||||
@@ -173,8 +172,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
|
||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
BaseDragLayer dl = getPopupContainer();
|
||||
final boolean cameFromNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
|
||||
if (!cameFromNavBar && !dl.isEventOverView(this, ev)) {
|
||||
if (!dl.isEventOverView(this, ev)) {
|
||||
mLauncher.getUserEventDispatcher().logActionTapOutside(
|
||||
LoggerUtils.newContainerTarget(ContainerType.DEEPSHORTCUTS));
|
||||
close(true);
|
||||
@@ -192,10 +190,6 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
|
||||
* @return the container if shown or null.
|
||||
*/
|
||||
public static PopupContainerWithArrow showForIcon(BubbleTextView icon) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"PopupContainerWithArrow.showForIcon");
|
||||
}
|
||||
Launcher launcher = Launcher.getLauncher(icon.getContext());
|
||||
if (getOpen(launcher) != null) {
|
||||
// There is already an items container open, so don't open this one.
|
||||
|
||||
@@ -233,11 +233,6 @@ public abstract class AbstractStateChangeTouchController
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"AbstractStateChangeTouchController.onDragStart() called with: start = [" +
|
||||
start + "]");
|
||||
}
|
||||
mStartState = mLauncher.getStateManager().getState();
|
||||
if (mStartState == ALL_APPS) {
|
||||
mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS;
|
||||
@@ -269,11 +264,6 @@ public abstract class AbstractStateChangeTouchController
|
||||
public boolean onDrag(float displacement) {
|
||||
float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
|
||||
float progress = deltaProgress + mStartProgress;
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"AbstractStateChangeTouchController.onDrag() called with: displacement = [" +
|
||||
displacement + "], progress = [" + progress + "]");
|
||||
}
|
||||
updateProgress(progress);
|
||||
boolean isDragTowardPositive = mSwipeDirection.isPositive(
|
||||
displacement - mDisplacementShift);
|
||||
@@ -393,12 +383,6 @@ public abstract class AbstractStateChangeTouchController
|
||||
? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS;
|
||||
targetState = (interpolatedProgress > successProgress) ? mToState : mFromState;
|
||||
}
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"AbstractStateChangeTouchController.onDragEnd() called with: velocity = [" +
|
||||
velocity + "], fling = [" + fling + "], target state: " +
|
||||
targetState.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
final float endProgress;
|
||||
final float startProgress;
|
||||
|
||||
@@ -66,14 +66,6 @@ public class ItemClickHandler {
|
||||
}
|
||||
|
||||
private static void onClick(View v, String sourceContainer) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onClick() called with: v = [" + v.getClass().getSimpleName() +
|
||||
"], sourceContainer = [" +
|
||||
(sourceContainer != null ?
|
||||
sourceContainer.getClass().getSimpleName() : "null")
|
||||
+ "]");
|
||||
}
|
||||
// Make sure that rogue clicks don't get through while allapps is launching, or after the
|
||||
// view has detached (it's possible for this to happen if the view is removed mid touch).
|
||||
if (v.getWindowToken() == null) {
|
||||
|
||||
@@ -74,10 +74,6 @@ public class ItemLongClickListener {
|
||||
}
|
||||
|
||||
private static boolean onAllAppsItemLongClick(View v) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onAllAppsItemLongClick");
|
||||
}
|
||||
Launcher launcher = Launcher.getLauncher(v.getContext());
|
||||
if (!canStartDrag(launcher)) return false;
|
||||
// When we have exited all apps or are in transition, disregard long clicks
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorMatrix;
|
||||
@@ -26,12 +27,34 @@ import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.uioverrides.WallpaperColorInfo;
|
||||
|
||||
/**
|
||||
* Various utility methods associated with theming.
|
||||
*/
|
||||
public class Themes {
|
||||
|
||||
public static int getActivityThemeRes(Context context) {
|
||||
WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(context);
|
||||
boolean darkTheme;
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
Configuration configuration = context.getResources().getConfiguration();
|
||||
int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
|
||||
} else {
|
||||
darkTheme = wallpaperColorInfo.isDark();
|
||||
}
|
||||
|
||||
if (darkTheme) {
|
||||
return wallpaperColorInfo.supportsDarkText() ?
|
||||
R.style.AppTheme_Dark_DarkText : R.style.AppTheme_Dark;
|
||||
} else {
|
||||
return wallpaperColorInfo.supportsDarkText() ?
|
||||
R.style.AppTheme_DarkText : R.style.AppTheme;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDefaultBodyFont(Context context) {
|
||||
TypedArray ta = context.obtainStyledAttributes(android.R.style.TextAppearance_DeviceDefault,
|
||||
new int[]{android.R.attr.fontFamily});
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.view.View.AccessibilityDelegate;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.dot.DotInfo;
|
||||
|
||||
/**
|
||||
@@ -56,6 +57,19 @@ public interface ActivityContext {
|
||||
|
||||
DeviceProfile getDeviceProfile();
|
||||
|
||||
/**
|
||||
* Device profile to be used by UI elements which are shown directly on top of the wallpaper
|
||||
* and whose presentation is tied to the wallpaper (and physical device) and not the activity
|
||||
* configuration.
|
||||
*/
|
||||
default DeviceProfile getWallpaperDeviceProfile() {
|
||||
return getDeviceProfile();
|
||||
}
|
||||
|
||||
default RotationMode getRotationMode() {
|
||||
return RotationMode.NORMAL;
|
||||
}
|
||||
|
||||
static ActivityContext lookupContext(Context context) {
|
||||
if (context instanceof ActivityContext) {
|
||||
return (ActivityContext) context;
|
||||
|
||||
@@ -22,13 +22,19 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
@@ -74,18 +80,33 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
}
|
||||
};
|
||||
|
||||
protected final int[] mTmpXY = new int[2];
|
||||
// Touch is being dispatched through the normal view dispatch system
|
||||
private static final int TOUCH_DISPATCHING_VIEW = 1 << 0;
|
||||
// Touch is being dispatched through the normal view dispatch system, and started at the
|
||||
// system gesture region
|
||||
private static final int TOUCH_DISPATCHING_GESTURE = 1 << 1;
|
||||
// Touch is being dispatched through a proxy from InputMonitor
|
||||
private static final int TOUCH_DISPATCHING_PROXY = 1 << 2;
|
||||
|
||||
protected final float[] mTmpXY = new float[2];
|
||||
protected final float[] mTmpRectPoints = new float[4];
|
||||
protected final Rect mHitRect = new Rect();
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private final RectF mSystemGestureRegion = new RectF();
|
||||
private int mTouchDispatchState = 0;
|
||||
|
||||
protected final T mActivity;
|
||||
private final MultiValueAlpha mMultiValueAlpha;
|
||||
|
||||
// All the touch controllers for the view
|
||||
protected TouchController[] mControllers;
|
||||
// Touch controller which is currently active for the normal view dispatch
|
||||
protected TouchController mActiveController;
|
||||
private TouchCompleteListener mTouchCompleteListener;
|
||||
// Touch controller which is being used for the proxy events
|
||||
protected TouchController mProxyTouchController;
|
||||
|
||||
// Object controlling the current touch interaction
|
||||
private Object mCurrentTouchOwner;
|
||||
private TouchCompleteListener mTouchCompleteListener;
|
||||
|
||||
public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
|
||||
super(context, attrs);
|
||||
@@ -113,33 +134,29 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
return findActiveController(ev);
|
||||
}
|
||||
|
||||
protected boolean findActiveController(MotionEvent ev) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"mActiveController = null");
|
||||
}
|
||||
mActiveController = null;
|
||||
|
||||
private TouchController findControllerToHandleTouch(MotionEvent ev) {
|
||||
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
|
||||
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"setting controller1: " + topView.getClass().getSimpleName());
|
||||
}
|
||||
mActiveController = topView;
|
||||
return true;
|
||||
return topView;
|
||||
}
|
||||
|
||||
for (TouchController controller : mControllers) {
|
||||
if (controller.onControllerInterceptTouchEvent(ev)) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"setting controller1: " + controller.getClass().getSimpleName());
|
||||
}
|
||||
mActiveController = controller;
|
||||
return true;
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean findActiveController(MotionEvent ev) {
|
||||
mActiveController = null;
|
||||
if ((mTouchDispatchState & (TOUCH_DISPATCHING_GESTURE | TOUCH_DISPATCHING_PROXY)) == 0) {
|
||||
// Only look for controllers if we are not dispatching from gesture area and proxy is
|
||||
// not active
|
||||
mActiveController = findControllerToHandleTouch(ev);
|
||||
|
||||
if (mActiveController != null) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,17 +222,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
}
|
||||
|
||||
if (mActiveController != null) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"BaseDragLayer before onControllerTouchEvent " +
|
||||
mActiveController.getClass().getSimpleName());
|
||||
}
|
||||
return mActiveController.onControllerTouchEvent(ev);
|
||||
} else {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"BaseDragLayer no controller");
|
||||
}
|
||||
// In case no child view handled the touch event, we may not get onIntercept anymore
|
||||
return findActiveController(ev);
|
||||
}
|
||||
@@ -223,39 +231,74 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
return dispatchTouchEvent(this, ev);
|
||||
}
|
||||
switch (ev.getAction()) {
|
||||
case ACTION_DOWN: {
|
||||
float x = ev.getX();
|
||||
float y = ev.getY();
|
||||
mTouchDispatchState |= TOUCH_DISPATCHING_VIEW;
|
||||
|
||||
public boolean dispatchTouchEvent(Object caller, MotionEvent ev) {
|
||||
return verifyTouchDispatch(caller, ev) && super.dispatchTouchEvent(ev);
|
||||
if ((y < mSystemGestureRegion.top
|
||||
|| x < mSystemGestureRegion.left
|
||||
|| x > (getWidth() - mSystemGestureRegion.right)
|
||||
|| y > (getHeight() - mSystemGestureRegion.bottom))) {
|
||||
mTouchDispatchState |= TOUCH_DISPATCHING_GESTURE;
|
||||
} else {
|
||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_CANCEL:
|
||||
case ACTION_UP:
|
||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
|
||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW;
|
||||
break;
|
||||
}
|
||||
super.dispatchTouchEvent(ev);
|
||||
|
||||
// We want to get all events so that mTouchDispatchSource is maintained properly
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@param caller} is allowed to dispatch {@param ev} on this view,
|
||||
* false otherwise.
|
||||
* Called before we are about to receive proxy events.
|
||||
*
|
||||
* @return false if we can't handle proxy at this time
|
||||
*/
|
||||
private boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
|
||||
int action = ev.getAction();
|
||||
if (action == ACTION_DOWN) {
|
||||
if (mCurrentTouchOwner != null) {
|
||||
// Another touch in progress.
|
||||
ev.setAction(ACTION_CANCEL);
|
||||
super.dispatchTouchEvent(ev);
|
||||
ev.setAction(action);
|
||||
}
|
||||
mCurrentTouchOwner = caller;
|
||||
return true;
|
||||
}
|
||||
if (mCurrentTouchOwner != caller) {
|
||||
// Someone else is controlling the touch
|
||||
public boolean prepareProxyEventStarting() {
|
||||
mProxyTouchController = null;
|
||||
if ((mTouchDispatchState & TOUCH_DISPATCHING_VIEW) != 0 && mActiveController != null) {
|
||||
// We are already dispatching using view system and have an active controller, we can't
|
||||
// handle another controller.
|
||||
|
||||
// This flag was already cleared in proxy ACTION_UP or ACTION_CANCEL. Added here just
|
||||
// to be safe
|
||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
|
||||
return false;
|
||||
}
|
||||
if (action == ACTION_UP || action == ACTION_CANCEL) {
|
||||
mCurrentTouchOwner = null;
|
||||
}
|
||||
|
||||
mTouchDispatchState |= TOUCH_DISPATCHING_PROXY;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxies the touch events to the gesture handlers
|
||||
*/
|
||||
public boolean proxyTouchEvent(MotionEvent ev) {
|
||||
boolean handled;
|
||||
if (mProxyTouchController != null) {
|
||||
handled = mProxyTouchController.onControllerTouchEvent(ev);
|
||||
} else {
|
||||
mProxyTouchController = findControllerToHandleTouch(ev);
|
||||
handled = mProxyTouchController != null;
|
||||
}
|
||||
int action = ev.getAction();
|
||||
if (action == ACTION_UP || action == ACTION_CANCEL) {
|
||||
mProxyTouchController = null;
|
||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the rect of the descendant in this DragLayer's coordinates
|
||||
*
|
||||
@@ -264,14 +307,16 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
* @return The factor by which this descendant is scaled relative to this DragLayer.
|
||||
*/
|
||||
public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
|
||||
mTmpXY[0] = 0;
|
||||
mTmpXY[1] = 0;
|
||||
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
|
||||
|
||||
r.set(mTmpXY[0], mTmpXY[1],
|
||||
(int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
|
||||
(int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
|
||||
return scale;
|
||||
mTmpRectPoints[0] = 0;
|
||||
mTmpRectPoints[1] = 0;
|
||||
mTmpRectPoints[2] = descendant.getWidth();
|
||||
mTmpRectPoints[3] = descendant.getHeight();
|
||||
float s = getDescendantCoordRelativeToSelf(descendant, mTmpRectPoints);
|
||||
r.left = Math.round(Math.min(mTmpRectPoints[0], mTmpRectPoints[2]));
|
||||
r.top = Math.round(Math.min(mTmpRectPoints[1], mTmpRectPoints[3]));
|
||||
r.right = Math.round(Math.max(mTmpRectPoints[0], mTmpRectPoints[2]));
|
||||
r.bottom = Math.round(Math.max(mTmpRectPoints[1], mTmpRectPoints[3]));
|
||||
return s;
|
||||
}
|
||||
|
||||
public float getLocationInDragLayer(View child, int[] loc) {
|
||||
@@ -281,6 +326,14 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
}
|
||||
|
||||
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
|
||||
mTmpXY[0] = coord[0];
|
||||
mTmpXY[1] = coord[1];
|
||||
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
|
||||
Utilities.roundArray(mTmpXY, coord);
|
||||
return scale;
|
||||
}
|
||||
|
||||
public float getDescendantCoordRelativeToSelf(View descendant, float[] coord) {
|
||||
return getDescendantCoordRelativeToSelf(descendant, coord, false);
|
||||
}
|
||||
|
||||
@@ -296,17 +349,27 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
* this scale factor is assumed to be equal in X and Y, and so if at any point this
|
||||
* assumption fails, we will need to return a pair of scale factors.
|
||||
*/
|
||||
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
|
||||
public float getDescendantCoordRelativeToSelf(View descendant, float[] coord,
|
||||
boolean includeRootScroll) {
|
||||
return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
|
||||
coord, includeRootScroll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, float[])}.
|
||||
*/
|
||||
public void mapCoordInSelfToDescendant(View descendant, float[] coord) {
|
||||
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
|
||||
*/
|
||||
public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
|
||||
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
|
||||
mTmpXY[0] = coord[0];
|
||||
mTmpXY[1] = coord[1];
|
||||
Utilities.mapCoordInSelfToDescendant(descendant, this, mTmpXY);
|
||||
Utilities.roundArray(mTmpXY, coord);
|
||||
}
|
||||
|
||||
public void getViewRectRelativeToSelf(View v, Rect r) {
|
||||
@@ -423,4 +486,13 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public void updateTouchExcludeRegion(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_Q) {
|
||||
Insets gestureInsets = insets.getMandatorySystemGestureInsets();
|
||||
mSystemGestureRegion.set(gestureInsets.left, gestureInsets.top,
|
||||
gestureInsets.right, gestureInsets.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
|
||||
@@ -23,6 +26,7 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
@@ -61,23 +65,23 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
|
||||
/**
|
||||
* A view that is created to look like another view with the purpose of creating fluid animations.
|
||||
*/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class FloatingIconView extends View implements Animator.AnimatorListener, ClipPathView {
|
||||
|
||||
public static final float SHAPE_PROGRESS_DURATION = 0.15f;
|
||||
private static final int FADE_DURATION_MS = 200;
|
||||
private static final Rect sTmpRect = new Rect();
|
||||
private static final Object[] sTmpObjArray = new Object[1];
|
||||
|
||||
private Runnable mEndRunnable;
|
||||
private CancellationSignal mLoadIconSignal;
|
||||
|
||||
private final int mBlurSizeOutline;
|
||||
|
||||
private boolean mIsVerticalBarLayout = false;
|
||||
private boolean mIsAdaptiveIcon = false;
|
||||
|
||||
private @Nullable Drawable mForeground;
|
||||
@@ -185,14 +189,16 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
* @param v The view to copy
|
||||
* @param positionOut Rect that will hold the size and position of v.
|
||||
*/
|
||||
private void matchPositionOf(Launcher launcher, View v, Rect positionOut) {
|
||||
Utilities.getLocationBoundsForView(launcher, v, positionOut);
|
||||
final LayoutParams lp = new LayoutParams(positionOut.width(), positionOut.height());
|
||||
private void matchPositionOf(Launcher launcher, View v, RectF positionOut) {
|
||||
getLocationBoundsForView(launcher, v, positionOut);
|
||||
final LayoutParams lp = new LayoutParams(
|
||||
Math.round(positionOut.width()),
|
||||
Math.round(positionOut.height()));
|
||||
lp.ignoreInsets = true;
|
||||
|
||||
// Position the floating view exactly on top of the original
|
||||
lp.leftMargin = positionOut.left;
|
||||
lp.topMargin = positionOut.top;
|
||||
lp.leftMargin = Math.round(positionOut.left);
|
||||
lp.topMargin = Math.round(positionOut.top);
|
||||
setLayoutParams(lp);
|
||||
// Set the properties here already to make sure they are available when running the first
|
||||
// animation frame.
|
||||
@@ -200,6 +206,57 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
+ lp.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location bounds of a view.
|
||||
* - For DeepShortcutView, we return the bounds of the icon view.
|
||||
* - For BubbleTextView, we return the icon bounds.
|
||||
*/
|
||||
private void getLocationBoundsForView(Launcher launcher, View v, RectF outRect) {
|
||||
final boolean isBubbleTextView = v instanceof BubbleTextView;
|
||||
final boolean isFolderIcon = v instanceof FolderIcon;
|
||||
|
||||
// Deep shortcut views have their icon drawn in a separate view.
|
||||
final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
|
||||
|
||||
final View targetView;
|
||||
boolean ignoreTransform = false;
|
||||
|
||||
if (v instanceof DeepShortcutView) {
|
||||
targetView = ((DeepShortcutView) v).getIconView();
|
||||
} else if (fromDeepShortcutView) {
|
||||
DeepShortcutView view = (DeepShortcutView) v.getParent();
|
||||
targetView = view.getIconView();
|
||||
} else if ((isBubbleTextView || isFolderIcon) && v.getTag() instanceof ItemInfo
|
||||
&& (((ItemInfo) v.getTag()).container == CONTAINER_DESKTOP
|
||||
|| ((ItemInfo) v.getTag()).container == CONTAINER_HOTSEAT)) {
|
||||
targetView = v;
|
||||
ignoreTransform = true;
|
||||
} else {
|
||||
targetView = v;
|
||||
}
|
||||
|
||||
float[] points = new float[] {0, 0, targetView.getWidth(), targetView.getHeight()};
|
||||
Utilities.getDescendantCoordRelativeToAncestor(targetView, launcher.getDragLayer(), points,
|
||||
false, ignoreTransform);
|
||||
|
||||
float viewLocationLeft = Math.min(points[0], points[2]);
|
||||
float viewLocationTop = Math.min(points[1], points[3]);
|
||||
|
||||
final Rect iconRect = new Rect();
|
||||
if (isBubbleTextView && !fromDeepShortcutView) {
|
||||
((BubbleTextView) v).getIconBounds(iconRect);
|
||||
} else if (isFolderIcon) {
|
||||
((FolderIcon) v).getPreviewBounds(iconRect);
|
||||
} else {
|
||||
iconRect.set(0, 0, Math.abs(Math.round(points[2] - points[0])),
|
||||
Math.abs(Math.round(points[3] - points[1])));
|
||||
}
|
||||
viewLocationLeft += iconRect.left;
|
||||
viewLocationTop += iconRect.top;
|
||||
outRect.set(viewLocationLeft, viewLocationTop, viewLocationLeft + iconRect.width(),
|
||||
viewLocationTop + iconRect.height());
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void getIcon(Launcher launcher, View v, ItemInfo info, boolean isOpening,
|
||||
Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
|
||||
@@ -207,10 +264,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
Drawable drawable = null;
|
||||
boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||
if (!supportsAdaptiveIcons && v instanceof BubbleTextView) {
|
||||
// Similar to DragView, we simply use the BubbleTextView icon here.
|
||||
drawable = ((BubbleTextView) v).getIcon();
|
||||
}
|
||||
Drawable btvIcon = v instanceof BubbleTextView ? ((BubbleTextView) v).getIcon() : null;
|
||||
if (info instanceof SystemShortcut) {
|
||||
if (v instanceof ImageView) {
|
||||
drawable = ((ImageView) v).getDrawable();
|
||||
@@ -219,10 +273,24 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
} else {
|
||||
drawable = v.getBackground();
|
||||
}
|
||||
}
|
||||
if (drawable == null) {
|
||||
drawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
|
||||
false, new Object[1]);
|
||||
} else {
|
||||
if (supportsAdaptiveIcons) {
|
||||
drawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
|
||||
false, sTmpObjArray);
|
||||
if (!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
// The drawable we get back is not an adaptive icon, so we need to use the
|
||||
// BubbleTextView icon that is already legacy treated.
|
||||
drawable = btvIcon;
|
||||
}
|
||||
} else {
|
||||
if (v instanceof BubbleTextView) {
|
||||
// Similar to DragView, we simply use the BubbleTextView icon here.
|
||||
drawable = btvIcon;
|
||||
} else {
|
||||
drawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
|
||||
false, sTmpObjArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drawable finalDrawable = drawable == null ? null
|
||||
@@ -273,7 +341,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
}
|
||||
|
||||
float aspectRatio = launcher.getDeviceProfile().aspectRatio;
|
||||
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
if (mIsVerticalBarLayout) {
|
||||
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
|
||||
} else {
|
||||
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
|
||||
@@ -318,8 +386,13 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
mBgDrawableBounds.set(mFinalDrawableBounds);
|
||||
Utilities.scaleRectAboutCenter(mBgDrawableBounds, scale);
|
||||
// Since the drawable is at the top of the view, we need to offset to keep it centered.
|
||||
mBgDrawableBounds.offsetTo(mBgDrawableBounds.left,
|
||||
(int) (mFinalDrawableBounds.top * scale));
|
||||
if (mIsVerticalBarLayout) {
|
||||
mBgDrawableBounds.offsetTo((int) (mFinalDrawableBounds.left * scale),
|
||||
mBgDrawableBounds.top);
|
||||
} else {
|
||||
mBgDrawableBounds.offsetTo(mBgDrawableBounds.left,
|
||||
(int) (mFinalDrawableBounds.top * scale));
|
||||
}
|
||||
mBackground.setBounds(mBgDrawableBounds);
|
||||
}
|
||||
|
||||
@@ -405,11 +478,12 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
* @param isOpening True if this view replaces the icon for app open animation.
|
||||
*/
|
||||
public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
|
||||
boolean hideOriginal, Rect positionOut, boolean isOpening, FloatingIconView recycle) {
|
||||
boolean hideOriginal, RectF positionOut, boolean isOpening, FloatingIconView recycle) {
|
||||
if (recycle != null) {
|
||||
recycle.recycle();
|
||||
}
|
||||
FloatingIconView view = recycle != null ? recycle : new FloatingIconView(launcher);
|
||||
view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
|
||||
|
||||
// Match the position of the original view.
|
||||
view.matchPositionOf(launcher, originalView, positionOut);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.views;
|
||||
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
|
||||
/**
|
||||
* Indicates that a view can be transposed.
|
||||
*/
|
||||
public interface Transposable {
|
||||
|
||||
RotationMode getRotationMode();
|
||||
}
|
||||
@@ -99,7 +99,8 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
|
||||
android:label="LauncherTestApp">
|
||||
android:label="LauncherTestApp"
|
||||
android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
@@ -111,5 +112,77 @@
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts"/>
|
||||
</activity>
|
||||
<activity-alias android:name="Activity2"
|
||||
android:label="TestActivity2"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity3"
|
||||
android:label="TestActivity3"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity4"
|
||||
android:label="TestActivity4"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity5"
|
||||
android:label="TestActivity5"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity6"
|
||||
android:label="TestActivity6"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity7"
|
||||
android:label="TestActivity7"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity8"
|
||||
android:label="TestActivity8"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity9"
|
||||
android:label="TestActivity9"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity10"
|
||||
android:label="TestActivity10"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity1 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity10 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity2 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity3 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity4 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity5 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity6 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity7 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity8 extends Activity {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.testcomponent;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Base activity with utility methods to help automate testing.
|
||||
*/
|
||||
public class MainActivity9 extends Activity {
|
||||
}
|
||||
@@ -17,6 +17,11 @@ package com.android.launcher3.ui;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_3BUTTON_OVERLAY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_GESTURAL_OVERLAY;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -24,11 +29,13 @@ import static java.lang.System.exit;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
@@ -57,6 +64,7 @@ import com.android.launcher3.util.rule.LauncherActivityRule;
|
||||
import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
@@ -67,6 +75,7 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -102,6 +111,68 @@ public abstract class AbstractLauncherUiTest {
|
||||
}
|
||||
if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
|
||||
mLauncher = new LauncherInstrumentation(instrumentation);
|
||||
|
||||
// b/130558787; b/131419978
|
||||
if (TestHelpers.isInLauncherProcess() && !LauncherInstrumentation.needSlowGestures()) {
|
||||
try {
|
||||
Class systemProps = Class.forName("android.os.SystemProperties");
|
||||
Method getInt = systemProps.getMethod("getInt", String.class, int.class);
|
||||
int apiLevel = (int) getInt.invoke(null, "ro.product.first_api_level", 0);
|
||||
|
||||
if (apiLevel >= Build.VERSION_CODES.P) {
|
||||
setActiveOverlay(NAV_BAR_MODE_2BUTTON_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.TWO_BUTTON);
|
||||
}
|
||||
if (apiLevel >= Build.VERSION_CODES.O && apiLevel < Build.VERSION_CODES.P) {
|
||||
setActiveOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.ZERO_BUTTON);
|
||||
}
|
||||
if (apiLevel < Build.VERSION_CODES.O) {
|
||||
setActiveOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.THREE_BUTTON);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveOverlay(String overlayPackage,
|
||||
LauncherInstrumentation.NavigationModel expectedMode) {
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_3BUTTON_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY);
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_2BUTTON_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_2BUTTON_OVERLAY);
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_GESTURAL_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY);
|
||||
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
if (mLauncher.getNavigationModel() == expectedMode) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Assert.fail("Couldn't switch to " + overlayPackage);
|
||||
}
|
||||
|
||||
private void setOverlayPackageEnabled(String overlayPackage, boolean enable) {
|
||||
Log.d(TAG, "setOverlayPackageEnabled: " + overlayPackage + " " + enable);
|
||||
final String action = enable ? "enable" : "disable";
|
||||
try {
|
||||
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
|
||||
"cmd overlay " + action + " " + overlayPackage);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
@@ -357,6 +428,22 @@ public abstract class AbstractLauncherUiTest {
|
||||
mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), LONG_WAIT_TIME_MS));
|
||||
}
|
||||
|
||||
protected void startTestActivity(int activityNumber) {
|
||||
final String packageName = getAppPackageName();
|
||||
final Instrumentation instrumentation = getInstrumentation();
|
||||
final Intent intent = instrumentation.getContext().getPackageManager().
|
||||
getLaunchIntentForPackage(packageName);
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setComponent(new ComponentName(packageName,
|
||||
"com.android.launcher3.tests.Activity" + activityNumber));
|
||||
instrumentation.getTargetContext().startActivity(intent);
|
||||
assertTrue(packageName + " didn't start",
|
||||
mDevice.wait(
|
||||
Until.hasObject(By.pkg(packageName).text("TestActivity" + activityNumber)),
|
||||
LONG_WAIT_TIME_MS));
|
||||
}
|
||||
|
||||
protected static String resolveSystemApp(String category) {
|
||||
return getInstrumentation().getContext().getPackageManager().resolveActivity(
|
||||
new Intent(Intent.ACTION_MAIN).addCategory(category),
|
||||
|
||||
@@ -71,7 +71,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
// Convert test to TAPL; b/131116002
|
||||
public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
|
||||
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
|
||||
|
||||
@@ -86,7 +86,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
// Convert test to TAPL; b/131116002
|
||||
public void testCustomProfileLoaded_with_widget() throws Exception {
|
||||
// A non-restored widget with no config screen gets restored automatically.
|
||||
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
|
||||
@@ -106,7 +106,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
// Convert test to TAPL; b/131116002
|
||||
public void testCustomProfileLoaded_with_folder() throws Exception {
|
||||
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
|
||||
.addApp(SETTINGS_APP, SETTINGS_APP)
|
||||
|
||||
@@ -33,7 +33,6 @@ import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.TestProtocol;
|
||||
import com.android.launcher3.popup.ArrowPopup;
|
||||
import com.android.launcher3.tapl.AllApps;
|
||||
import com.android.launcher3.tapl.AppIcon;
|
||||
@@ -239,12 +238,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
// Test starting a workspace app.
|
||||
final AppIcon app = workspace.tryGetWorkspaceAppIcon("Chrome");
|
||||
assertNotNull("No Chrome app in workspace", app);
|
||||
assertNotNull("AppIcon.launch returned null",
|
||||
app.launch(resolveSystemApp(Intent.CATEGORY_APP_BROWSER)));
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
}
|
||||
|
||||
public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
|
||||
@@ -329,20 +322,19 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testDragAppIcon() throws Throwable {
|
||||
try {
|
||||
TestProtocol.sDebugTracing = true;
|
||||
// 1. Open all apps and wait for load complete.
|
||||
// 2. Drag icon to homescreen.
|
||||
// 3. Verify that the icon works on homescreen.
|
||||
mLauncher.getWorkspace().
|
||||
switchToAllApps().
|
||||
getAppIcon(APP_NAME).
|
||||
dragToWorkspace().
|
||||
getWorkspaceAppIcon(APP_NAME).
|
||||
launch(getAppPackageName());
|
||||
} finally {
|
||||
TestProtocol.sDebugTracing = false;
|
||||
}
|
||||
// 1. Open all apps and wait for load complete.
|
||||
// 2. Drag icon to homescreen.
|
||||
// 3. Verify that the icon works on homescreen.
|
||||
mLauncher.getWorkspace().
|
||||
switchToAllApps().
|
||||
getAppIcon(APP_NAME).
|
||||
dragToWorkspace().
|
||||
getWorkspaceAppIcon(APP_NAME).
|
||||
launch(getAppPackageName());
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -71,25 +71,25 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
// Convert test to TAPL b/131116002
|
||||
public void testWidgetConfig() throws Throwable {
|
||||
runTest(false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
@Ignore // b/121280703
|
||||
public void testWidgetConfig_rotate() throws Throwable {
|
||||
runTest(true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
// Convert test to TAPL b/131116002
|
||||
public void testConfigCancelled() throws Throwable {
|
||||
runTest(false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
@Ignore // b/121280703
|
||||
public void testConfigCancelled_rotate() throws Throwable {
|
||||
runTest(true, false);
|
||||
}
|
||||
|
||||
@@ -49,19 +49,19 @@ public class AddWidgetTest extends AbstractLauncherUiTest {
|
||||
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
public void testDragIcon_portrait() throws Throwable {
|
||||
lockRotation(true);
|
||||
performTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Convert test to TAPL and enable them; b/131116002
|
||||
@Ignore // b/121280703
|
||||
public void testDragIcon_landscape() throws Throwable {
|
||||
lockRotation(false);
|
||||
performTest();
|
||||
}
|
||||
|
||||
// Convert to TAPL b/131116002
|
||||
private void performTest() throws Throwable {
|
||||
clearHomescreen();
|
||||
mActivityMonitor.startLauncher();
|
||||
|
||||
@@ -69,6 +69,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
if (mLauncher.getNavigationModel() != ZERO_BUTTON) {
|
||||
final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
|
||||
allAppsContainer.setGestureMargins(0, 0, 0, navBar.getVisibleBounds().height() + 1);
|
||||
} else {
|
||||
allAppsContainer.setGestureMargins(0, 0, 0, 100);
|
||||
}
|
||||
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
|
||||
if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
* Common overview pane for both Launcher and fallback recents
|
||||
*/
|
||||
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
private static final int FLING_SPEED = 1500;
|
||||
private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 500 : 1500;
|
||||
private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
|
||||
|
||||
BaseOverview(LauncherInstrumentation launcher) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user