Merging from ub-launcher3-master @ build 6269120 am: 8f03c5c1ce am: 8df766f1ba
Change-Id: I1a28c59fb27daeb956eb743b3e2d3356a421d192
This commit is contained in:
@@ -71,6 +71,7 @@
|
||||
<application
|
||||
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||
android:fullBackupOnly="true"
|
||||
android:backupInForeground="true"
|
||||
android:fullBackupContent="@xml/backupscheme"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher_home"
|
||||
|
||||
@@ -8,9 +8,26 @@ adamcohen@google.com
|
||||
hyunyoungs@google.com
|
||||
mrcasey@google.com
|
||||
sunnygoyal@google.com
|
||||
awickham@google.com
|
||||
twickham@google.com
|
||||
winsonc@google.com
|
||||
zakcohen@google.com
|
||||
santie@google.com
|
||||
vadimt@google.com
|
||||
mett@google.com
|
||||
jonmiranda@google.com
|
||||
pinyaoting@google.com
|
||||
sfufa@google.com
|
||||
gwasserman@google.com
|
||||
jamesoleary@google.com
|
||||
joshtrask@google.com
|
||||
mrenouf@google.com
|
||||
mkephart@google.com
|
||||
hwwang@google.com
|
||||
tracyzhou@google.com
|
||||
peanutbutter@google.com
|
||||
xuqiu@google.com
|
||||
sreyasr@google.com
|
||||
|
||||
per-file FeatureFlags.java = sunnygoyal@google.com, adamcohen@google.com
|
||||
per-file BaseFlags.java = sunnygoyal@google.com, adamcohen@google.com
|
||||
per-file FeatureFlags.java, globs = set noparent
|
||||
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
|
||||
|
||||
@@ -155,6 +155,7 @@ enum ControlType {
|
||||
OVERVIEW_ACTIONS_SCREENSHOT_BUTTON = 25;
|
||||
OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
|
||||
SELECT_MODE_CLOSE_BUTTON = 27;
|
||||
SELECT_MODE_ITEM = 28;
|
||||
}
|
||||
|
||||
enum TipType {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""
|
||||
android:taskAffinity="${packageName}.launcher"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:taskAffinity="${packageName}.launcher"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
|
||||
|
||||
@@ -28,4 +28,9 @@
|
||||
android:clipToPadding="false"
|
||||
android:outlineProvider="none"
|
||||
android:theme="@style/HomeScreenElementTheme" />
|
||||
|
||||
<include
|
||||
android:id="@+id/overview_actions_view"
|
||||
layout="@layout/overview_actions_holder" />
|
||||
|
||||
</com.android.quickstep.fallback.RecentsRootView>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,17 +13,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.InsettableFrameLayout
|
||||
<com.android.quickstep.views.LauncherRecentsView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<com.android.quickstep.views.LauncherRecentsView
|
||||
android:id="@+id/overview_panel_recents"
|
||||
android:theme="@style/HomeScreenElementTheme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:accessibilityPaneTitle="@string/accessibility_recent_apps"
|
||||
android:visibility="invisible" />
|
||||
</com.android.launcher3.InsettableFrameLayout>
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:accessibilityPaneTitle="@string/accessibility_recent_apps"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:theme="@style/HomeScreenElementTheme"
|
||||
android:visibility="invisible" />
|
||||
|
||||
@@ -35,25 +35,27 @@
|
||||
|
||||
<TextView
|
||||
style="@style/TextHeadline"
|
||||
android:id="@+id/hotseat_edu_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||
android:paddingRight="@dimen/bottom_sheet_edu_padding"
|
||||
android:text="@string/hotseat_migrate_title"
|
||||
android:text="@string/hotseat_edu_title_migrate"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/hotseat_edu_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:fontFamily="roboto-medium"
|
||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||
android:paddingRight="@dimen/bottom_sheet_edu_padding"
|
||||
android:text="@string/hotseat_migrate_message"
|
||||
android:text="@string/hotseat_edu_message_migrate"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
@@ -83,7 +85,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/hotseat_migrate_accept"
|
||||
android:text="@string/hotseat_edu_accept"
|
||||
android:textAlignment="textEnd"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
@@ -91,7 +93,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/no_thanks"
|
||||
android:text="@string/hotseat_migrate_dismiss"
|
||||
android:text="@string/hotseat_edu_dismiss"
|
||||
android:layout_gravity="start"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
@@ -23,10 +23,4 @@
|
||||
|
||||
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
||||
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
|
||||
|
||||
<!-- Swipe up to home related -->
|
||||
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
|
||||
<dimen name="swipe_up_y_overshoot">10dp</dimen>
|
||||
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
|
||||
|
||||
</resources>
|
||||
+9
-3
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
@@ -39,6 +38,7 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -50,6 +50,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.SpringAnimationBuilder;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
@@ -88,7 +89,8 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
|
||||
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
|
||||
|
||||
AppWindowAnimationHelper helper = new AppWindowAnimationHelper(mLauncher);
|
||||
AppWindowAnimationHelper helper =
|
||||
new AppWindowAnimationHelper(recentsView.getPagedViewOrientedState(), mLauncher);
|
||||
anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets,
|
||||
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
|
||||
|
||||
@@ -197,7 +199,11 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
|
||||
RecentsView.CONTENT_ALPHA, values);
|
||||
case INDEX_RECENTS_TRANSLATE_X_ANIM:
|
||||
return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), VIEW_TRANSLATE_X)
|
||||
PagedOrientationHandler orientationHandler =
|
||||
((RecentsView)mLauncher.getOverviewPanel()).getPagedViewOrientedState()
|
||||
.getOrientationHandler();
|
||||
FloatProperty<View> translate = orientationHandler.getPrimaryViewTranslate();
|
||||
return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), translate)
|
||||
.setDampingRatio(0.8f)
|
||||
.setStiffness(250)
|
||||
.setValues(values)
|
||||
|
||||
+20
-7
@@ -27,11 +27,15 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.WorkspaceLayoutManager;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.Themes;
|
||||
@@ -61,16 +65,25 @@ public class HotseatEduController {
|
||||
mNotification = createNotification();
|
||||
}
|
||||
|
||||
void migrate() {
|
||||
boolean migrate() {
|
||||
Workspace workspace = mLauncher.getWorkspace();
|
||||
CellLayout firstScreen = workspace.getScreenWithId(WorkspaceLayoutManager.FIRST_SCREEN_ID);
|
||||
int toPage = Workspace.FIRST_SCREEN_ID;
|
||||
int toRow = mLauncher.getDeviceProfile().inv.numRows - 1;
|
||||
if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) {
|
||||
toPage = workspace.getScreenIdForPageIndex(workspace.getPageCount());
|
||||
toRow = 0;
|
||||
} else if (!firstScreen.makeSpaceForHotseatMigration(true)) {
|
||||
return false;
|
||||
}
|
||||
ViewGroup hotseatVG = mLauncher.getHotseat().getShortcutsAndWidgets();
|
||||
int workspacePageCount = mLauncher.getWorkspace().getPageCount();
|
||||
for (int i = 0; i < hotseatVG.getChildCount(); i++) {
|
||||
View child = hotseatVG.getChildAt(i);
|
||||
ItemInfo tag = (ItemInfo) child.getTag();
|
||||
mLauncher.getModelWriter().moveItemInDatabase(tag,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP, workspacePageCount, tag.screenId,
|
||||
0);
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP, toPage, tag.screenId, toRow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeNotification() {
|
||||
@@ -93,7 +106,7 @@ public class HotseatEduController {
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
||||
CharSequence name = mLauncher.getString(R.string.hotseat_migrate_title);
|
||||
CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title);
|
||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name,
|
||||
importance);
|
||||
@@ -104,8 +117,8 @@ public class HotseatEduController {
|
||||
Intent intent = new Intent(mLauncher.getApplicationContext(), mLauncher.getClass());
|
||||
intent = new NotificationHandler().addToIntent(intent);
|
||||
|
||||
CharSequence name = mLauncher.getString(R.string.hotseat_migrate_prompt_title);
|
||||
String description = mLauncher.getString(R.string.hotseat_migrate_prompt_content);
|
||||
CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title);
|
||||
String description = mLauncher.getString(R.string.hotseat_edu_prompt_content);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mLauncher,
|
||||
NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(name)
|
||||
|
||||
+76
-21
@@ -26,6 +26,7 @@ import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.launcher3.CellLayout;
|
||||
@@ -34,7 +35,9 @@ import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.WorkspaceLayoutManager;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -49,12 +52,24 @@ import java.util.List;
|
||||
public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
|
||||
|
||||
private static final int DEFAULT_CLOSE_DURATION = 200;
|
||||
protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
|
||||
|
||||
// We don't migrate if user has more than SAME_PAGE_MAX_ROWS rows of item in their screen
|
||||
private static final int SAME_PAGE_MAX_ROWS = 2;
|
||||
|
||||
private static final int MIGRATE_SAME_PAGE = 0;
|
||||
private static final int MIGRATE_NEW_PAGE = 1;
|
||||
private static final int MIGRATE_NO_MIGRATE = 2;
|
||||
|
||||
public static boolean shown = false;
|
||||
|
||||
private final Rect mInsets = new Rect();
|
||||
private View mHotseatWrapper;
|
||||
private CellLayout mSampleHotseat;
|
||||
private TextView mEduHeading;
|
||||
private TextView mEduContent;
|
||||
private Button mDismissBtn;
|
||||
|
||||
private int mMigrationMode = MIGRATE_SAME_PAGE;
|
||||
|
||||
public void setHotseatEduController(HotseatEduController hotseatEduController) {
|
||||
mHotseatEduController = hotseatEduController;
|
||||
@@ -78,6 +93,8 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
super.onFinishInflate();
|
||||
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
|
||||
mSampleHotseat = findViewById(R.id.sample_prediction);
|
||||
mEduHeading = findViewById(R.id.hotseat_edu_heading);
|
||||
mEduContent = findViewById(R.id.hotseat_edu_content);
|
||||
|
||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||
Rect padding = grid.getHotseatLayoutPadding();
|
||||
@@ -87,24 +104,27 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
|
||||
|
||||
Button turnOnBtn = findViewById(R.id.turn_predictions_on);
|
||||
turnOnBtn.setOnClickListener(this::onMigrate);
|
||||
turnOnBtn.setOnClickListener(this::onAccept);
|
||||
|
||||
Button learnMoreBtn = findViewById(R.id.no_thanks);
|
||||
learnMoreBtn.setOnClickListener(this::onKeepDefault);
|
||||
mDismissBtn = findViewById(R.id.no_thanks);
|
||||
mDismissBtn.setOnClickListener(this::onDismiss);
|
||||
|
||||
}
|
||||
|
||||
private void onMigrate(View v) {
|
||||
if (mHotseatEduController == null) return;
|
||||
private void onAccept(View v) {
|
||||
if (mMigrationMode == MIGRATE_NO_MIGRATE || !mHotseatEduController.migrate()) {
|
||||
onDismiss(v);
|
||||
return;
|
||||
}
|
||||
handleClose(true);
|
||||
mHotseatEduController.migrate();
|
||||
mHotseatEduController.finishOnboarding();
|
||||
logUserAction(true);
|
||||
Toast.makeText(mLauncher, R.string.hotseat_items_migrated, Toast.LENGTH_LONG).show();
|
||||
int toastStringRes = mMigrationMode == MIGRATE_SAME_PAGE
|
||||
? R.string.hotseat_items_migrated : R.string.hotseat_items_migrated_alt;
|
||||
Toast.makeText(mLauncher, toastStringRes, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void onKeepDefault(View v) {
|
||||
if (mHotseatEduController == null) return;
|
||||
private void onDismiss(View v) {
|
||||
Toast.makeText(getContext(), R.string.hotseat_no_migration, Toast.LENGTH_LONG).show();
|
||||
mHotseatEduController.finishOnboarding();
|
||||
logUserAction(false);
|
||||
@@ -148,6 +168,8 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
|
||||
target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
|
||||
: HYBRID_HOTSEAT_CANCELED;
|
||||
// encoding migration type on pageIndex
|
||||
target.pageIndex = mMigrationMode;
|
||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
||||
}
|
||||
@@ -161,6 +183,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
||||
}
|
||||
|
||||
private void animateOpen() {
|
||||
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||
return;
|
||||
@@ -183,17 +206,12 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
handleClose(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens User education dialog with a list of suggested apps
|
||||
*/
|
||||
public void show(List<WorkspaceItemInfo> predictions) {
|
||||
if (getParent() != null
|
||||
|| predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons) {
|
||||
return;
|
||||
}
|
||||
attachToContainer();
|
||||
logOnBoardingSeen();
|
||||
animateOpen();
|
||||
@Override
|
||||
protected int getScrimColor(Context context) {
|
||||
return FINAL_SCRIM_BG_COLOR;
|
||||
}
|
||||
|
||||
private void populatePreview(List<WorkspaceItemInfo> predictions) {
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
||||
WorkspaceItemInfo info = predictions.get(i);
|
||||
PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
|
||||
@@ -204,6 +222,43 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachToContainer() {
|
||||
super.attachToContainer();
|
||||
if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) {
|
||||
mEduContent.setText(R.string.hotseat_edu_message_migrate_alt);
|
||||
mMigrationMode = MIGRATE_NEW_PAGE;
|
||||
return;
|
||||
}
|
||||
CellLayout page = mLauncher.getWorkspace().getScreenWithId(
|
||||
WorkspaceLayoutManager.FIRST_SCREEN_ID);
|
||||
|
||||
int maxItemsOnPage = SAME_PAGE_MAX_ROWS * mLauncher.getDeviceProfile().inv.numColumns
|
||||
+ (FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0);
|
||||
if (page.getShortcutsAndWidgets().getChildCount() > maxItemsOnPage
|
||||
|| !page.makeSpaceForHotseatMigration(false)) {
|
||||
mMigrationMode = MIGRATE_NO_MIGRATE;
|
||||
mEduContent.setText(R.string.hotseat_edu_message_no_migrate);
|
||||
mEduHeading.setText(R.string.hotseat_edu_title_no_migrate);
|
||||
mDismissBtn.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens User education dialog with a list of suggested apps
|
||||
*/
|
||||
public void show(List<WorkspaceItemInfo> predictions) {
|
||||
if (getParent() != null
|
||||
|| predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons
|
||||
|| mHotseatEduController == null) {
|
||||
return;
|
||||
}
|
||||
attachToContainer();
|
||||
logOnBoardingSeen();
|
||||
animateOpen();
|
||||
populatePreview(predictions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for HotseatPredictionUserEdu dialog
|
||||
*/
|
||||
|
||||
+2
-2
@@ -80,10 +80,10 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
mMotionPauseDetector.clear();
|
||||
|
||||
super.onDragStart(start);
|
||||
super.onDragStart(start, startDisplacement);
|
||||
|
||||
if (handlingOverviewAnim()) {
|
||||
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ public class NavBarToHomeTouchController implements TouchController,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
initCurrentAnimation();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -94,8 +94,8 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
super.onDragStart(start);
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
super.onDragStart(start, startDisplacement);
|
||||
|
||||
mReachedOverview = false;
|
||||
}
|
||||
|
||||
+3
-2
@@ -116,12 +116,13 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
|
||||
mLauncher = launcher;
|
||||
mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
|
||||
mShelfPeekAnim = mLauncher.getShelfPeekAnim();
|
||||
mRecentsView = mLauncher.getOverviewPanel();
|
||||
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
|
||||
mYRange = LayoutUtils.getShelfTrackingDistance(mLauncher, mLauncher.getDeviceProfile());
|
||||
mYRange = LayoutUtils.getShelfTrackingDistance(
|
||||
mLauncher, mLauncher.getDeviceProfile());
|
||||
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
|
||||
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
|
||||
R.dimen.motion_pause_detector_min_displacement_from_app);
|
||||
mRecentsView = mLauncher.getOverviewPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -92,8 +92,8 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
super.onDragStart(start);
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
super.onDragStart(start, startDisplacement);
|
||||
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
|
||||
mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
|
||||
ActivityManagerWrapper.getInstance()
|
||||
|
||||
+28
-9
@@ -36,6 +36,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.FlingBlockCheck;
|
||||
@@ -77,7 +78,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
public TaskViewTouchController(T activity) {
|
||||
mActivity = activity;
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
mDetector = new SingleAxisSwipeDetector(activity, this, SingleAxisSwipeDetector.VERTICAL);
|
||||
SingleAxisSwipeDetector.Direction dir =
|
||||
mRecentsView.getPagedOrientationHandler().getOppositeSwipeDirection();
|
||||
mDetector = new SingleAxisSwipeDetector(activity, this, dir);
|
||||
}
|
||||
|
||||
private boolean canInterceptTouch() {
|
||||
@@ -105,6 +108,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
|
||||
@Override
|
||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||
if ((ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL)
|
||||
&& mCurrentAnimation == null) {
|
||||
clearState();
|
||||
}
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mNoIntercept = !canInterceptTouch();
|
||||
if (mNoIntercept) {
|
||||
@@ -125,6 +132,11 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
TaskView view = mRecentsView.getTaskViewAt(i);
|
||||
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
|
||||
.isEventOverView(view, ev)) {
|
||||
// Disable swiping up and down if the task overlay is modal.
|
||||
if (view.isTaskOverlayModal()) {
|
||||
mTaskBeingDragged = null;
|
||||
break;
|
||||
}
|
||||
mTaskBeingDragged = view;
|
||||
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
|
||||
// Don't allow swipe down to open if we don't support swipe up
|
||||
@@ -181,15 +193,18 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
mPendingAnimation = null;
|
||||
}
|
||||
|
||||
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||
mCurrentAnimationIsGoingUp = goingUp;
|
||||
BaseDragLayer dl = mActivity.getDragLayer();
|
||||
long maxDuration = (long) (2 * dl.getHeight());
|
||||
|
||||
final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl);
|
||||
long maxDuration = (long) (2 * secondaryLayerDimension);
|
||||
int verticalFactor = -orientationHandler.getTaskDismissDirectionFactor();
|
||||
int secondaryTaskDimension = orientationHandler.getSecondaryDimension(mTaskBeingDragged);
|
||||
if (goingUp) {
|
||||
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
|
||||
true /* animateTaskView */, true /* removeTask */, maxDuration);
|
||||
|
||||
mEndDisplacement = -mTaskBeingDragged.getHeight();
|
||||
mEndDisplacement = -secondaryTaskDimension;
|
||||
} else {
|
||||
mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
|
||||
mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
|
||||
@@ -198,6 +213,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
|
||||
mEndDisplacement = dl.getHeight() - mTempCords[1];
|
||||
}
|
||||
mEndDisplacement *= verticalFactor;
|
||||
|
||||
if (mCurrentAnimation != null) {
|
||||
mCurrentAnimation.setOnCancelRunnable(null);
|
||||
@@ -211,9 +227,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||
if (mCurrentAnimation == null) {
|
||||
reInitAnimationController(mDetector.wasInitialTouchPositive());
|
||||
reInitAnimationController(orientationHandler.isGoingUp(startDisplacement));
|
||||
mDisplacementShift = 0;
|
||||
} else {
|
||||
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
|
||||
@@ -224,9 +241,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement) {
|
||||
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||
float totalDisplacement = displacement + mDisplacementShift;
|
||||
boolean isGoingUp =
|
||||
totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
|
||||
boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
|
||||
orientationHandler.isGoingUp(totalDisplacement);
|
||||
if (isGoingUp != mCurrentAnimationIsGoingUp) {
|
||||
reInitAnimationController(isGoingUp);
|
||||
mFlingBlockCheck.blockFling();
|
||||
@@ -253,11 +271,12 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
if (blockedFling) {
|
||||
fling = false;
|
||||
}
|
||||
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||
float progress = mCurrentAnimation.getProgressFraction();
|
||||
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
|
||||
if (fling) {
|
||||
logAction = Touch.FLING;
|
||||
boolean goingUp = velocity < 0;
|
||||
boolean goingUp = orientationHandler.isGoingUp(velocity);
|
||||
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
|
||||
} else {
|
||||
logAction = Touch.SWIPE;
|
||||
|
||||
+2
-1
@@ -125,7 +125,8 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
|
||||
return anim;
|
||||
}
|
||||
|
||||
final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(mActivity);
|
||||
final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(
|
||||
mRecentsView.getPagedViewOrientedState(), mActivity);
|
||||
|
||||
// At this point, the activity is already started and laid-out. Get the home-bounds
|
||||
// relative to the screen using the rootView of the activity.
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
@@ -32,6 +31,7 @@ import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
@@ -46,6 +46,10 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.model.PagedViewOrientedState;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.PortraitPagedViewHandler;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
|
||||
@@ -75,18 +79,16 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
private static final String TAG = "BaseSwipeUpHandler";
|
||||
protected static final Rect TEMP_RECT = new Rect();
|
||||
|
||||
// Start resisting when swiping past this factor of mTransitionDragLength.
|
||||
private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = ENABLE_OVERVIEW_ACTIONS.get()
|
||||
? 2.8f : 1.4f;
|
||||
// This is how far down we can scale down, where 0f is full screen and 1f is recents.
|
||||
private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = ENABLE_OVERVIEW_ACTIONS.get()
|
||||
? 3.6f : 1.8f;
|
||||
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
|
||||
|
||||
// The distance needed to drag to reach the task size in recents.
|
||||
protected int mTransitionDragLength;
|
||||
// How much further we can drag past recents, as a factor of mTransitionDragLength.
|
||||
protected float mDragLengthFactor = 1;
|
||||
// Start resisting when swiping past this factor of mTransitionDragLength.
|
||||
private float mDragLengthFactorStartPullback = 1f;
|
||||
// This is how far down we can scale down, where 0f is full screen and 1f is recents.
|
||||
private float mDragLengthFactorMaxPullback = 1f;
|
||||
|
||||
protected final Context mContext;
|
||||
protected final RecentsAnimationDeviceState mDeviceState;
|
||||
@@ -94,7 +96,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
protected final BaseActivityInterface<T> mActivityInterface;
|
||||
protected final InputConsumerController mInputConsumer;
|
||||
|
||||
protected final AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||
protected final TransformParams mTransformParams = new TransformParams();
|
||||
|
||||
// Shift in the range of [0, 1].
|
||||
@@ -123,6 +125,8 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
protected boolean mCanceled;
|
||||
protected int mFinishingRecentsAnimationForNewTaskId = -1;
|
||||
|
||||
private PagedViewOrientedState mOrientedState;
|
||||
|
||||
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
|
||||
GestureState gestureState, InputConsumerController inputConsumer) {
|
||||
mContext = context;
|
||||
@@ -132,20 +136,18 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
mActivityInitListener =
|
||||
mActivityInterface.createActivityInitListener(this::onActivityInit);
|
||||
mInputConsumer = inputConsumer;
|
||||
|
||||
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
|
||||
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
|
||||
|
||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
||||
.getDeviceProfile(mContext));
|
||||
.getDeviceProfile(mContext));
|
||||
}
|
||||
|
||||
protected void performHapticFeedback() {
|
||||
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
|
||||
return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode navBarRotationMode) {
|
||||
return mRecentsView != null ? mRecentsView.getEventDispatcher(navBarRotationMode) : null;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -158,12 +160,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
} else {
|
||||
float translation = Math.max(displacement, 0);
|
||||
shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
|
||||
if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
|
||||
if (shift > mDragLengthFactorStartPullback) {
|
||||
float pullbackProgress = Utilities.getProgress(shift,
|
||||
DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
|
||||
mDragLengthFactorStartPullback, mDragLengthFactor);
|
||||
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
|
||||
shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
|
||||
* (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
|
||||
shift = mDragLengthFactorStartPullback + pullbackProgress
|
||||
* (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,10 +328,25 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
// we otherwise use the minimized home bounds provided by the system.
|
||||
mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
|
||||
}
|
||||
int displayRotation = 0;
|
||||
if (mOrientedState != null) {
|
||||
// TODO(b/150300347): The first recents animation after launcher is started with the
|
||||
// foreground app not in landscape will look funky until that bug is fixed
|
||||
displayRotation = mOrientedState.getDisplayRotation();
|
||||
}
|
||||
RotationHelper.getTargetRectForRotation(TEMP_RECT, dp.widthPx, dp.heightPx,
|
||||
displayRotation);
|
||||
mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
|
||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||
// We can drag all the way to the top of the screen.
|
||||
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
|
||||
// TODO(b/149609070): Landscape apps are currently limited in
|
||||
// their ability to scale past the target rect.
|
||||
float dragFactor = (float) dp.heightPx / mTransitionDragLength;
|
||||
mDragLengthFactor = displayRotation == 0 ? dragFactor : Math.min(1.0f, dragFactor);
|
||||
Pair<Float, Float> dragFactorStartAndMaxProgress =
|
||||
mActivityInterface.getSwipeUpPullbackStartAndMaxProgress();
|
||||
mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first;
|
||||
mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +355,17 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
*/
|
||||
protected abstract boolean moveWindowWithRecentsScroll();
|
||||
|
||||
protected abstract boolean onActivityInit(Boolean alreadyOnHome);
|
||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||
T createdActivity = mActivityInterface.getCreatedActivity();
|
||||
if (createdActivity != null) {
|
||||
mOrientedState = ((RecentsView) createdActivity.getOverviewPanel())
|
||||
.getPagedViewOrientedState();
|
||||
mAppWindowAnimationHelper = new AppWindowAnimationHelper(mOrientedState, mContext);
|
||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
||||
.getDeviceProfile(mContext));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to create a input proxy for the running task
|
||||
@@ -382,23 +409,32 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
*/
|
||||
protected void applyTransformUnchecked() {
|
||||
float shift = mCurrentShift.value;
|
||||
float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
|
||||
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
|
||||
mAppWindowAnimationHelper.getTargetRect().width());
|
||||
float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
|
||||
float taskSize = getOrientationHandler()
|
||||
.getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
|
||||
float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
|
||||
mTransformParams.setProgress(shift)
|
||||
.setOffsetX(offsetX)
|
||||
.setOffset(offset)
|
||||
.setOffsetScale(offsetScale)
|
||||
.setTargetSet(mRecentsAnimationTargets)
|
||||
.setLauncherOnTop(true);
|
||||
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
||||
}
|
||||
|
||||
private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) {
|
||||
float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + mPageSpacing;
|
||||
float interpolation = Math.min(1, offsetX / distanceToReachEdge);
|
||||
private float getTaskCurveScaleForOffset(float offset, float taskSize) {
|
||||
int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
|
||||
float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
|
||||
float interpolation = Math.min(1, offset / distanceToReachEdge);
|
||||
return TaskView.getCurveScaleForInterpolation(interpolation);
|
||||
}
|
||||
|
||||
protected PagedOrientationHandler getOrientationHandler() {
|
||||
if (mOrientedState == null) {
|
||||
return new PortraitPagedViewHandler();
|
||||
}
|
||||
return mOrientedState.getOrientationHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that transforms the current app window into the home app.
|
||||
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
|
||||
@@ -406,16 +442,19 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
*/
|
||||
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||
HomeAnimationFactory homeAnimationFactory) {
|
||||
final RectF startRect = new RectF(
|
||||
mAppWindowAnimationHelper.applyTransform(
|
||||
mTransformParams.setProgress(startProgress)
|
||||
.setTargetSet(mRecentsAnimationTargets)
|
||||
.setLauncherOnTop(false)));
|
||||
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
||||
|
||||
final View floatingView = homeAnimationFactory.getFloatingView();
|
||||
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
|
||||
final RectF startRect = new RectF(
|
||||
mAppWindowAnimationHelper.applyTransform(
|
||||
mTransformParams.setProgress(startProgress)
|
||||
.setTargetSet(mRecentsAnimationTargets)
|
||||
.setLauncherOnTop(false)));
|
||||
if (isFloatingIconView) {
|
||||
RotationHelper.mapInverseRectFromNormalOrientation(startRect,
|
||||
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
|
||||
}
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
|
||||
if (isFloatingIconView) {
|
||||
FloatingIconView fiv = (FloatingIconView) floatingView;
|
||||
anim.addAnimatorListener(fiv);
|
||||
@@ -435,6 +474,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||
// FolderIconView can be seen morphing into the icon shape.
|
||||
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
|
||||
final RectF rotatedRect = new RectF();
|
||||
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
|
||||
|
||||
@Override
|
||||
@@ -445,9 +485,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
|
||||
.setCurrentRect(currentRect)
|
||||
.setTargetAlpha(getWindowAlpha(progress));
|
||||
rotatedRect.set(currentRect);
|
||||
if (isFloatingIconView) {
|
||||
RotationHelper.mapRectFromNormalOrientation(rotatedRect,
|
||||
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
|
||||
mTransformParams.setCornerRadius(endRadius * progress + startRadius
|
||||
* (1f - progress));
|
||||
* (1f - progress));
|
||||
}
|
||||
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
||||
|
||||
|
||||
+2
-1
@@ -30,10 +30,11 @@ import android.graphics.RectF;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.touch.PortraitPagedViewHandler;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.fallback.FallbackRecentsView;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
|
||||
@@ -161,12 +161,12 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
|
||||
@Override
|
||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||
super.onActivityInit(alreadyOnHome);
|
||||
mActivity = mActivityInterface.getCreatedActivity();
|
||||
mRecentsView = mActivity.getOverviewPanel();
|
||||
linkRecentsViewScroll();
|
||||
mRecentsView.setDisallowScrollToClearAll(true);
|
||||
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
|
||||
|
||||
mRecentsView.setZoomProgress(1);
|
||||
|
||||
if (!mContinuingLastGesture) {
|
||||
@@ -177,6 +177,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
}
|
||||
}
|
||||
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
|
||||
mDeviceState.enableMultipleRegions(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -419,7 +420,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
this::createNewInputProxyHandler);
|
||||
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
|
||||
anim.addAnimatorListener(endListener);
|
||||
anim.start(mEndVelocityPxPerMs);
|
||||
anim.start(mContext, mEndVelocityPxPerMs);
|
||||
mFinishAnimation = RunningWindowAnim.wrap(anim);
|
||||
} else {
|
||||
|
||||
@@ -469,7 +470,8 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
HomeAnimationFactory factory = new HomeAnimationFactory() {
|
||||
@Override
|
||||
public RectF getWindowTargetRect() {
|
||||
return HomeAnimationFactory.getDefaultWindowTargetRect(mDp);
|
||||
return HomeAnimationFactory
|
||||
.getDefaultWindowTargetRect(mRecentsView.getPagedOrientationHandler(), mDp);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+30
-7
@@ -38,6 +38,7 @@ import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
@@ -54,6 +55,7 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
@@ -78,6 +80,8 @@ import java.util.function.Predicate;
|
||||
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
|
||||
|
||||
private Runnable mAdjustInterpolatorsRunnable;
|
||||
private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
|
||||
BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
|
||||
|
||||
@Override
|
||||
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
|
||||
@@ -91,6 +95,11 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
|
||||
return mSwipeUpPullbackStartAndMaxProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionCancelled(boolean activityVisible) {
|
||||
Launcher launcher = getCreatedActivity();
|
||||
@@ -176,7 +185,8 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
||||
if (canUseWorkspaceView) {
|
||||
return iconLocation;
|
||||
} else {
|
||||
return HomeAnimationFactory.getDefaultWindowTargetRect(dp);
|
||||
return HomeAnimationFactory
|
||||
.getDefaultWindowTargetRect(recentsView.getPagedOrientationHandler(), dp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,23 +278,28 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
||||
float scrollOffsetX = recentsView.getScrollOffset();
|
||||
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
|
||||
|
||||
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
|
||||
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
|
||||
float fromTranslation = attached ? offscreenX - scrollOffsetX : 0;
|
||||
float toTranslation = attached ? 0 : offscreenX - scrollOffsetX;
|
||||
launcher.getStateManager()
|
||||
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
|
||||
|
||||
PagedOrientationHandler pagedOrientationHandler =
|
||||
recentsView.getPagedViewOrientedState().getOrientationHandler();
|
||||
if (!recentsView.isShown() && animate) {
|
||||
recentsView.setTranslationX(fromTranslationX);
|
||||
pagedOrientationHandler
|
||||
.getPrimaryViewTranslate().set(recentsView, fromTranslation);
|
||||
} else {
|
||||
fromTranslationX = recentsView.getTranslationX();
|
||||
fromTranslation =
|
||||
pagedOrientationHandler.getPrimaryViewTranslate().get(recentsView);
|
||||
}
|
||||
|
||||
if (!animate) {
|
||||
recentsView.setTranslationX(toTranslationX);
|
||||
pagedOrientationHandler
|
||||
.getPrimaryViewTranslate().set(recentsView, toTranslation);
|
||||
} else {
|
||||
launcher.getStateManager().createStateElementAnimation(
|
||||
INDEX_RECENTS_TRANSLATE_X_ANIM,
|
||||
fromTranslationX, toTranslationX).start();
|
||||
fromTranslation, toTranslation).start();
|
||||
}
|
||||
|
||||
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
|
||||
@@ -377,6 +392,14 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
||||
return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1);
|
||||
});
|
||||
};
|
||||
|
||||
// Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
|
||||
float pullbackStartProgress = (0.75f - fromScaleAndTranslation.scale)
|
||||
/ (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
|
||||
float pullbackMaxProgress = (0.5f - fromScaleAndTranslation.scale)
|
||||
/ (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
|
||||
mSwipeUpPullbackStartAndMaxProgress = new Pair<>(
|
||||
pullbackStartProgress, pullbackMaxProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -261,6 +261,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
@Override
|
||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||
super.onActivityInit(alreadyOnHome);
|
||||
final T activity = mActivityInterface.getCreatedActivity();
|
||||
if (mActivity == activity) {
|
||||
return true;
|
||||
@@ -770,6 +771,16 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
if (endTarget == NEW_TASK) {
|
||||
SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask();
|
||||
}
|
||||
|
||||
if (endTarget == RECENTS || endTarget == HOME) {
|
||||
// Since we're now done quickStepping, we want to only listen for touch events
|
||||
// for the main orientation's nav bar, instead of multiple
|
||||
mDeviceState.enableMultipleRegions(false);
|
||||
}
|
||||
|
||||
if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
|
||||
return LAST_TASK;
|
||||
}
|
||||
@@ -929,7 +940,8 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
|
||||
}
|
||||
});
|
||||
windowAnim.start(velocityPxPerMs);
|
||||
getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
|
||||
windowAnim.start(mContext, velocityPxPerMs);
|
||||
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
|
||||
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
||||
mLauncherTransitionController = null;
|
||||
|
||||
@@ -183,7 +183,8 @@ public final class RecentsActivity extends BaseRecentsActivity {
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
AnimatorSet target = new AnimatorSet();
|
||||
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
|
||||
AppWindowAnimationHelper helper = new AppWindowAnimationHelper(this);
|
||||
AppWindowAnimationHelper helper = new AppWindowAnimationHelper(
|
||||
mFallbackRecentsView.getPagedViewOrientedState(), this);
|
||||
target.play(getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
|
||||
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.plugins.OverscrollPlugin;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
@@ -67,6 +68,13 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
|
||||
forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class);
|
||||
|
||||
/**
|
||||
* @return a launcher-provided OverscrollPlugin if available, otherwise null
|
||||
*/
|
||||
public OverscrollPlugin getLocalOverscrollPlugin() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
|
||||
return new TaskOverlay();
|
||||
}
|
||||
@@ -87,5 +95,12 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
* Called when the overlay is no longer used.
|
||||
*/
|
||||
public void reset() { }
|
||||
|
||||
/**
|
||||
* Whether the overlay is modal, which means only tapping is enabled, but no swiping.
|
||||
*/
|
||||
public boolean isOverlayModal() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
-13
@@ -17,13 +17,7 @@ package com.android.quickstep;
|
||||
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
|
||||
@@ -56,6 +50,8 @@ import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -80,6 +76,7 @@ import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.AssistantUtilities;
|
||||
import com.android.quickstep.util.ProtoTracer;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.plugins.OverscrollPlugin;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
@@ -449,6 +446,8 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
|
||||
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
|
||||
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
|
||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||
|
||||
if (event.getAction() == ACTION_DOWN) {
|
||||
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
|
||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||
@@ -502,17 +501,32 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
|| previousGestureState.isRecentsAnimationRunning()
|
||||
? newBaseConsumer(previousGestureState, newGestureState, event)
|
||||
: mResetGestureInputConsumer;
|
||||
// TODO(b/149880412): 2 button landscape mode is wrecked. Fixit!
|
||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||
handleOrientationSetup(base);
|
||||
if (mDeviceState.canTriggerAssistantAction(event)) {
|
||||
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()
|
||||
&& (mOverscrollPlugin != null)
|
||||
&& mOverscrollPlugin.isActive()) {
|
||||
// Put the overscroll gesture as higher priority than the Assistant or base gestures
|
||||
base = new OverscrollInputConsumer(this, newGestureState, base, mInputMonitorCompat,
|
||||
mOverscrollPlugin);
|
||||
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
|
||||
OverscrollPlugin plugin = null;
|
||||
if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
|
||||
TaskOverlayFactory factory =
|
||||
TaskOverlayFactory.INSTANCE.get(getApplicationContext());
|
||||
plugin = factory.getLocalOverscrollPlugin(); // may be null
|
||||
}
|
||||
|
||||
// If not local plugin was forced, use the actual overscroll plugin if available.
|
||||
if (plugin == null && mOverscrollPlugin != null && mOverscrollPlugin.isActive()) {
|
||||
plugin = mOverscrollPlugin;
|
||||
}
|
||||
|
||||
if (plugin != null) {
|
||||
// Put the overscroll gesture as higher priority than the Assistant or base
|
||||
// gestures
|
||||
base = new OverscrollInputConsumer(this, newGestureState, base,
|
||||
mInputMonitorCompat, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
@@ -533,6 +547,22 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
return base;
|
||||
}
|
||||
|
||||
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
|
||||
if (!PagedView.sFlagForcedRotation) {
|
||||
return;
|
||||
}
|
||||
mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
|
||||
Launcher l = (Launcher) mOverviewComponentObserver
|
||||
.getActivityInterface().getCreatedActivity();
|
||||
if (l == null || !(l.getOverviewPanel() instanceof RecentsView)) {
|
||||
return;
|
||||
}
|
||||
((RecentsView)l.getOverviewPanel())
|
||||
.setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
|
||||
mDeviceState.getDisplayRotation());
|
||||
l.getDragLayer().recreateControllers();
|
||||
}
|
||||
|
||||
private InputConsumer newBaseConsumer(GestureState previousGestureState,
|
||||
GestureState gestureState, MotionEvent event) {
|
||||
if (mDeviceState.isKeyguardShowingOccluded()) {
|
||||
@@ -732,10 +762,18 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
FeatureFlags.dump(pw);
|
||||
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
|
||||
mDeviceState.dump(pw);
|
||||
mOverviewComponentObserver.dump(pw);
|
||||
if (mOverviewComponentObserver != null) {
|
||||
mOverviewComponentObserver.dump(pw);
|
||||
}
|
||||
if (mGestureState != null) {
|
||||
mGestureState.dump(pw);
|
||||
}
|
||||
pw.println("TouchState:");
|
||||
BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
|
||||
: mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
|
||||
boolean resumed = mOverviewComponentObserver != null
|
||||
&& mOverviewComponentObserver.getActivityInterface().isResumed();
|
||||
pw.println(" createdOverviewActivity=" + createdOverviewActivity);
|
||||
pw.println(" resumed=" + resumed);
|
||||
pw.println(" mConsumer=" + mConsumer.getName());
|
||||
ActiveGestureLog.INSTANCE.dump("", pw);
|
||||
|
||||
+5
@@ -195,4 +195,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
|
||||
}
|
||||
super.applyLoadPlan(tasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsVerticalLandscape() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -176,8 +176,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
// Proxy events to recents view
|
||||
if (mPassedWindowMoveSlop && mInteractionHandler != null
|
||||
&& !mRecentsViewDispatcher.hasConsumer()) {
|
||||
mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
|
||||
mNavBarPosition.getRotationMode()));
|
||||
mRecentsViewDispatcher.setConsumer(mInteractionHandler
|
||||
.getRecentsViewDispatcher(mNavBarPosition.getRotationMode()));
|
||||
}
|
||||
int edgeFlags = ev.getEdgeFlags();
|
||||
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
|
||||
@@ -364,7 +364,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
: mNavBarPosition.isLeftEdge()
|
||||
? -velocityX
|
||||
: velocityY;
|
||||
|
||||
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
|
||||
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
|
||||
mDownPos);
|
||||
|
||||
+42
-20
@@ -15,12 +15,6 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
@@ -28,6 +22,7 @@ import android.graphics.Matrix.ScaleToFit;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -37,6 +32,7 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.model.PagedViewOrientedState;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
@@ -50,6 +46,12 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
|
||||
import com.android.systemui.shared.system.TransactionCompat;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
/**
|
||||
* Utility class to handle window clip animation
|
||||
*/
|
||||
@@ -82,6 +84,7 @@ public class AppWindowAnimationHelper {
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final RectF mTmpRectF = new RectF();
|
||||
private final RectF mCurrentRectWithInsets = new RectF();
|
||||
private PagedViewOrientedState mOrientedState;
|
||||
// Corner radius of windows, in pixels
|
||||
private final float mWindowCornerRadius;
|
||||
// Corner radius of windows when they're in overview mode.
|
||||
@@ -100,20 +103,24 @@ public class AppWindowAnimationHelper {
|
||||
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
|
||||
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
|
||||
|
||||
public AppWindowAnimationHelper(Context context) {
|
||||
public AppWindowAnimationHelper(PagedViewOrientedState orientedState, Context context) {
|
||||
mOrientedState = orientedState;
|
||||
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
|
||||
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
|
||||
mTaskCornerRadius = TaskCornerRadius.get(context);
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
|
||||
}
|
||||
|
||||
public AppWindowAnimationHelper(Context context) {
|
||||
this(null, context);
|
||||
}
|
||||
|
||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||
mSourceInsets.set(target.contentInsets);
|
||||
mSourceStackBounds.set(target.sourceContainerBounds);
|
||||
|
||||
// TODO: Should sourceContainerBounds already have this offset?
|
||||
mSourceStackBounds.offsetTo(target.position.x, target.position.y);
|
||||
|
||||
}
|
||||
|
||||
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
|
||||
@@ -138,8 +145,9 @@ public class AppWindowAnimationHelper {
|
||||
// from the source rect. The difference between the target rect (scaled to the
|
||||
// source rect) is the amount to clip on each edge.
|
||||
RectF scaledTargetRect = new RectF(mTargetRect);
|
||||
Utilities.scaleRectFAboutCenter(scaledTargetRect,
|
||||
mSourceRect.width() / mTargetRect.width());
|
||||
float scale = getSrcToTargetScale();
|
||||
Utilities.scaleRectFAboutCenter(scaledTargetRect, scale);
|
||||
|
||||
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
|
||||
mSourceWindowClipInsets.set(
|
||||
Math.max(scaledTargetRect.left, 0),
|
||||
@@ -149,6 +157,16 @@ public class AppWindowAnimationHelper {
|
||||
mSourceRect.set(scaledTargetRect);
|
||||
}
|
||||
|
||||
private float getSrcToTargetScale() {
|
||||
if (mOrientedState == null ||
|
||||
(mOrientedState.getDisplayRotation() == Surface.ROTATION_0
|
||||
|| mOrientedState.getDisplayRotation() == Surface.ROTATION_180)) {
|
||||
return mSourceRect.width() / mTargetRect.width();
|
||||
} else {
|
||||
return mSourceRect.height() / mTargetRect.height();
|
||||
}
|
||||
}
|
||||
|
||||
public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
|
||||
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
|
||||
@@ -221,7 +239,6 @@ public class AppWindowAnimationHelper {
|
||||
layer = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
|
||||
// have to undo the scale.
|
||||
surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
|
||||
@@ -237,11 +254,16 @@ public class AppWindowAnimationHelper {
|
||||
mTmpRectF.set(mTargetRect);
|
||||
Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
|
||||
mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
|
||||
mCurrentRect.offset(params.mOffsetX, 0);
|
||||
if (mOrientedState == null || mOrientedState.areMultipleLayoutOrientationsDisabled()) {
|
||||
mCurrentRect.offset(params.mOffset, 0);
|
||||
} else {
|
||||
int displayRotation = mOrientedState.getDisplayRotation();
|
||||
mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect,
|
||||
params.mOffset, displayRotation);
|
||||
}
|
||||
}
|
||||
|
||||
updateClipRect(params);
|
||||
|
||||
return mCurrentRect;
|
||||
}
|
||||
|
||||
@@ -340,7 +362,7 @@ public class AppWindowAnimationHelper {
|
||||
* @return The source rect's scale and translation relative to the target rect.
|
||||
*/
|
||||
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
|
||||
float scale = mSourceRect.width() / mTargetRect.width();
|
||||
float scale = getSrcToTargetScale();
|
||||
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
|
||||
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
|
||||
}
|
||||
@@ -390,7 +412,7 @@ public class AppWindowAnimationHelper {
|
||||
|
||||
public static class TransformParams {
|
||||
private float mProgress;
|
||||
private float mOffsetX;
|
||||
private float mOffset;
|
||||
private float mOffsetScale;
|
||||
private @Nullable RectF mCurrentRect;
|
||||
private float mTargetAlpha;
|
||||
@@ -401,7 +423,7 @@ public class AppWindowAnimationHelper {
|
||||
|
||||
public TransformParams() {
|
||||
mProgress = 0;
|
||||
mOffsetX = 0;
|
||||
mOffset = 0;
|
||||
mOffsetScale = 1;
|
||||
mCurrentRect = null;
|
||||
mTargetAlpha = 1;
|
||||
@@ -453,8 +475,8 @@ public class AppWindowAnimationHelper {
|
||||
* the default), then offset the current rect by this amount after computing the rect based
|
||||
* on {@link #mProgress}.
|
||||
*/
|
||||
public TransformParams setOffsetX(float offsetX) {
|
||||
mOffsetX = offsetX;
|
||||
public TransformParams setOffset(float offset) {
|
||||
mOffset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -504,8 +526,8 @@ public class AppWindowAnimationHelper {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
public float getOffsetX() {
|
||||
return mOffsetX;
|
||||
public float getOffset() {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
public float getOffsetScale() {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.content.res.Resources;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
|
||||
@@ -28,6 +28,8 @@ import androidx.dynamicanimation.animation.SpringForce;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.FlingSpringAnim;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -103,7 +105,7 @@ public class RectFSpringAnim {
|
||||
private float mMinVisChange;
|
||||
private float mYOvershoot;
|
||||
|
||||
public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) {
|
||||
public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
|
||||
mStartRect = startRect;
|
||||
mTargetRect = targetRect;
|
||||
mCurrentCenterX = mStartRect.centerX();
|
||||
@@ -111,8 +113,9 @@ public class RectFSpringAnim {
|
||||
mTrackingBottomY = startRect.bottom < targetRect.bottom;
|
||||
mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
|
||||
|
||||
mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change);
|
||||
mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot);
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
|
||||
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
|
||||
}
|
||||
|
||||
public void onTargetPositionChanged() {
|
||||
@@ -137,7 +140,12 @@ public class RectFSpringAnim {
|
||||
mAnimatorListeners.add(animatorListener);
|
||||
}
|
||||
|
||||
public void start(PointF velocityPxPerMs) {
|
||||
/**
|
||||
* Starts the fling/spring animation.
|
||||
* @param context The activity context.
|
||||
* @param velocityPxPerMs Velocity of swipe in px/ms.
|
||||
*/
|
||||
public void start(Context context, PointF velocityPxPerMs) {
|
||||
// Only tell caller that we ended if both x and y animations have ended.
|
||||
OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
|
||||
mRectXAnimEnded = true;
|
||||
@@ -152,7 +160,7 @@ public class RectFSpringAnim {
|
||||
float endX = mTargetRect.centerX();
|
||||
float minXValue = Math.min(startX, endX);
|
||||
float maxXValue = Math.max(startX, endX);
|
||||
mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, startX, endX,
|
||||
mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
|
||||
velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);
|
||||
|
||||
float startVelocityY = velocityPxPerMs.y * 1000;
|
||||
@@ -162,14 +170,18 @@ public class RectFSpringAnim {
|
||||
float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
|
||||
float minYValue = Math.min(startY, endY - mYOvershoot);
|
||||
float maxYValue = Math.max(startY, endY);
|
||||
mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
|
||||
mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, startVelocityY,
|
||||
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
|
||||
|
||||
float minVisibleChange = Math.abs(1f / mStartRect.height());
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
|
||||
float stiffness = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
|
||||
|
||||
mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
|
||||
.setSpring(new SpringForce(1f)
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW))
|
||||
.setDampingRatio(damping)
|
||||
.setStiffness(stiffness))
|
||||
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
|
||||
.setMaxValue(1f)
|
||||
.setMinimumVisibleChange(minVisibleChange)
|
||||
|
||||
+7
-5
@@ -41,7 +41,9 @@ import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.anim.SpringAnimationBuilder;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
/**
|
||||
* Creates an animation where all the workspace items are moved into their final location,
|
||||
@@ -55,9 +57,6 @@ public class StaggeredWorkspaceAnim {
|
||||
|
||||
private static final float MAX_VELOCITY_PX_PER_S = 22f;
|
||||
|
||||
private static final float DAMPING_RATIO = 0.7f;
|
||||
private static final float STIFFNESS = 150f;
|
||||
|
||||
private final float mVelocity;
|
||||
private final float mSpringTransY;
|
||||
|
||||
@@ -177,9 +176,12 @@ public class StaggeredWorkspaceAnim {
|
||||
|
||||
v.setTranslationY(mSpringTransY);
|
||||
|
||||
ResourceProvider rp = DynamicResource.provider(v.getContext());
|
||||
float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
|
||||
float damping = rp.getFloat(R.dimen.staggered_damping_ratio);
|
||||
ObjectAnimator springTransY = new SpringAnimationBuilder<>(v, VIEW_TRANSLATE_Y)
|
||||
.setStiffness(STIFFNESS)
|
||||
.setDampingRatio(DAMPING_RATIO)
|
||||
.setStiffness(stiffness)
|
||||
.setDampingRatio(damping)
|
||||
.setMinimumVisibleChange(1f)
|
||||
.setEndValue(0)
|
||||
.setStartVelocity(mVelocity)
|
||||
|
||||
+32
-10
@@ -21,7 +21,7 @@ import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.quickstep.views.RecentsView.PageCallbacks;
|
||||
import com.android.quickstep.views.RecentsView.ScrollState;
|
||||
|
||||
@@ -44,21 +44,26 @@ public class ClearAllButton extends Button implements PageCallbacks {
|
||||
private float mContentAlpha = 1;
|
||||
private float mVisibilityAlpha = 1;
|
||||
|
||||
private final boolean mIsRtl;
|
||||
private boolean mIsRtl;
|
||||
|
||||
private int mScrollOffset;
|
||||
private RecentsView mParent;
|
||||
|
||||
public ClearAllButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mIsRtl = Utilities.isRtl(context.getResources());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mScrollOffset = mIsRtl ? mParent.getPaddingRight() / 2 : - mParent.getPaddingLeft() / 2;
|
||||
}
|
||||
|
||||
RecentsView parent = (RecentsView) getParent();
|
||||
mScrollOffset = mIsRtl ? parent.getPaddingRight() / 2 : - parent.getPaddingLeft() / 2;
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mParent = (RecentsView) getParent();
|
||||
mIsRtl = !mParent.getPagedOrientationHandler().getRecentsRtlSetting(getResources());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +78,21 @@ public class ClearAllButton extends Button implements PageCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
public void onLayoutChanged() {
|
||||
if (mParent == null) {
|
||||
return;
|
||||
}
|
||||
setRotation(mParent.getPagedOrientationHandler().getDegreesRotated());
|
||||
}
|
||||
|
||||
public void setRtl(boolean rtl) {
|
||||
if (mIsRtl == rtl) {
|
||||
return;
|
||||
}
|
||||
mIsRtl = rtl;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setVisibilityAlpha(float alpha) {
|
||||
if (mVisibilityAlpha != alpha) {
|
||||
mVisibilityAlpha = alpha;
|
||||
@@ -82,14 +102,16 @@ public class ClearAllButton extends Button implements PageCallbacks {
|
||||
|
||||
@Override
|
||||
public void onPageScroll(ScrollState scrollState) {
|
||||
float width = getWidth();
|
||||
if (width == 0) {
|
||||
PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
|
||||
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
|
||||
if (orientationSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float shift = Math.min(scrollState.scrollFromEdge, width);
|
||||
setTranslationX(mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift));
|
||||
mScrollAlpha = 1 - shift / width;
|
||||
float shift = Math.min(scrollState.scrollFromEdge, orientationSize);
|
||||
float translation = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
|
||||
orientationHandler.setPrimaryAndResetSecondaryTranslate(this, translation);
|
||||
mScrollAlpha = 1 - shift / orientationSize;
|
||||
updateAlpha();
|
||||
}
|
||||
|
||||
|
||||
+25
-10
@@ -42,10 +42,12 @@ import com.android.launcher3.Hotseat;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.StateListener;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
@@ -85,6 +87,10 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
}
|
||||
};
|
||||
|
||||
private RotationHelper.ForcedRotationChangedListener mForcedRotationChangedListener =
|
||||
isForcedRotation -> LauncherRecentsView.this
|
||||
.disableMultipleLayoutRotations(!isForcedRotation);
|
||||
|
||||
public LauncherRecentsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -180,19 +186,21 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
* @return The translationX to apply to this view so that the first task is just offscreen.
|
||||
*/
|
||||
public float getOffscreenTranslationX(float recentsScale) {
|
||||
float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX;
|
||||
LauncherState.ScaleAndTranslation overviewScaleAndTranslation =
|
||||
NORMAL.getOverviewScaleAndTranslation(mActivity);
|
||||
float offscreen = mOrientationHandler.getTranslationValue(overviewScaleAndTranslation);
|
||||
// Offset since scale pushes tasks outwards.
|
||||
getTaskSize(sTempRect);
|
||||
int taskWidth = sTempRect.width();
|
||||
offscreenX += taskWidth * (recentsScale - 1) / 2;
|
||||
int taskSize = mOrientationHandler.getPrimarySize(sTempRect);
|
||||
offscreen += taskSize * (recentsScale - 1) / 2;
|
||||
if (mRunningTaskTileHidden) {
|
||||
// The first task is hidden, so offset by its width.
|
||||
offscreenX -= (taskWidth + getPageSpacing()) * recentsScale;
|
||||
offscreen -= (taskSize + getPageSpacing()) * recentsScale;
|
||||
}
|
||||
if (isRtl()) {
|
||||
offscreenX = -offscreenX;
|
||||
offscreen = -offscreen;
|
||||
}
|
||||
return offscreenX;
|
||||
return offscreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -276,6 +284,11 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
return mTransformParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsVerticalLandscape() {
|
||||
return PagedView.sFlagForcedRotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
@@ -329,6 +342,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
super.onAttachedToWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener(
|
||||
mRecentsExtraCardPluginListener, RecentsExtraCard.class);
|
||||
mActivity.getRotationHelper().addForcedRotationCallback(mForcedRotationChangedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -336,22 +350,23 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
super.onDetachedFromWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(
|
||||
mRecentsExtraCardPluginListener);
|
||||
mActivity.getRotationHelper().removeForcedRotationCallback(mForcedRotationChangedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMinScrollX() {
|
||||
protected int computeMinScroll() {
|
||||
if (canComputeScrollX() && !mIsRtl) {
|
||||
return computeScrollX();
|
||||
}
|
||||
return super.computeMinScrollX();
|
||||
return super.computeMinScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMaxScrollX() {
|
||||
protected int computeMaxScroll() {
|
||||
if (canComputeScrollX() && mIsRtl) {
|
||||
return computeScrollX();
|
||||
}
|
||||
return super.computeMaxScrollX();
|
||||
return super.computeMaxScroll();
|
||||
}
|
||||
|
||||
private boolean canComputeScrollX() {
|
||||
|
||||
@@ -22,7 +22,6 @@ import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAG
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
@@ -30,6 +29,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
||||
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
@@ -52,7 +52,6 @@ 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;
|
||||
@@ -66,11 +65,14 @@ import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Property;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
@@ -80,26 +82,32 @@ import android.view.animation.Interpolator;
|
||||
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;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PropertyListBuilder;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
|
||||
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.ComponentKey;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
@@ -108,12 +116,14 @@ import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.ViewUtils;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
@@ -162,6 +172,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
};
|
||||
|
||||
private final OrientationEventListener mOrientationListener;
|
||||
private int mPreviousRotation;
|
||||
protected RecentsAnimationController mRecentsAnimationController;
|
||||
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
||||
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||
@@ -198,7 +210,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private boolean mDwbToastShown;
|
||||
protected boolean mDisallowScrollToClearAll;
|
||||
private boolean mOverlayEnabled;
|
||||
private boolean mFreezeViewVisibility;
|
||||
protected boolean mFreezeViewVisibility;
|
||||
|
||||
/**
|
||||
* TODO: Call reloadIdNeeded in onTaskStackChanged.
|
||||
@@ -268,15 +280,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
};
|
||||
|
||||
private final IPinnedStackAnimationListener mIPinnedStackAnimationListener =
|
||||
new IPinnedStackAnimationListener.Stub() {
|
||||
@Override
|
||||
public void onPinnedStackAnimationStarted() {
|
||||
// Needed for activities that auto-enter PiP, which will not trigger a remote
|
||||
// animation to be created
|
||||
mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
|
||||
}
|
||||
};
|
||||
private final PinnedStackAnimationListener mIPinnedStackAnimationListener =
|
||||
new PinnedStackAnimationListener();
|
||||
|
||||
// Used to keep track of the last requested task list id, so that we do not request to load the
|
||||
// tasks again if we have already requested it and the task list has not changed
|
||||
@@ -321,6 +326,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
// Keeps track of the index where the first TaskView should be
|
||||
private int mTaskViewStartIndex = 0;
|
||||
private View mActionsView;
|
||||
private boolean mGestureRunning = false;
|
||||
|
||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||
(inMultiWindowMode) -> {
|
||||
@@ -340,7 +347,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mActivity = (T) BaseActivity.fromContext(context);
|
||||
mModel = RecentsModel.INSTANCE.get(context);
|
||||
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
|
||||
mTempAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
|
||||
mTempAppWindowAnimationHelper =
|
||||
new AppWindowAnimationHelper(getPagedViewOrientedState(), context);
|
||||
|
||||
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
|
||||
.inflate(R.layout.overview_clear_all_button, this, false);
|
||||
@@ -348,7 +356,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
|
||||
10 /* initial size */);
|
||||
|
||||
mIsRtl = !Utilities.isRtl(getResources());
|
||||
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
|
||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
mTaskTopMargin = getResources()
|
||||
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
||||
@@ -368,9 +376,26 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
.getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
|
||||
setWillNotDraw(false);
|
||||
updateEmptyMessage();
|
||||
disableMultipleLayoutRotations(!supportsVerticalLandscape());
|
||||
|
||||
// Initialize quickstep specific cache params here, as this is constructed only once
|
||||
mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
|
||||
mOrientationListener = new OrientationEventListener(getContext()) {
|
||||
@Override
|
||||
public void onOrientationChanged(int i) {
|
||||
int rotation = RotationHelper.getRotationFromDegrees(i);
|
||||
if (mPreviousRotation != rotation) {
|
||||
animateRecentsRotationInPlace(rotation);
|
||||
if (rotation == 0) {
|
||||
showActionsView();
|
||||
} else {
|
||||
hideActionsView();
|
||||
}
|
||||
mPreviousRotation = rotation;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public OverScroller getScroller() {
|
||||
@@ -451,8 +476,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
|
||||
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
||||
mIdp.addOnChangeListener(this);
|
||||
mIPinnedStackAnimationListener.setActivity(mActivity);
|
||||
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
|
||||
mIPinnedStackAnimationListener);
|
||||
addActionsView();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -466,6 +493,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
|
||||
mIdp.removeOnChangeListener(this);
|
||||
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
|
||||
mIPinnedStackAnimationListener.setActivity(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -496,6 +524,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
public void setOverviewStateEnabled(boolean enabled) {
|
||||
if (supportsVerticalLandscape() && mOrientationListener.canDetectOrientation()) {
|
||||
if (enabled) {
|
||||
mOrientationListener.enable();
|
||||
} else {
|
||||
mOrientationListener.disable();
|
||||
}
|
||||
}
|
||||
mOverviewStateEnabled = enabled;
|
||||
updateTaskStackListenerState();
|
||||
if (!enabled) {
|
||||
@@ -573,6 +608,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
|
||||
// Enables swiping to the left or right only if the task overlay is not modal.
|
||||
if (getCurrentPageTaskView() == null || !getCurrentPageTaskView().isTaskOverlayModal()) {
|
||||
super.determineScrollingStart(ev, touchSlopScale);
|
||||
}
|
||||
}
|
||||
protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
|
||||
return true;
|
||||
}
|
||||
@@ -599,6 +641,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (getTaskViewCount() != requiredTaskCount) {
|
||||
if (indexOfChild(mClearAllButton) != -1) {
|
||||
removeView(mClearAllButton);
|
||||
hideActionsView();
|
||||
}
|
||||
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
|
||||
addView(mTaskViewPool.getView());
|
||||
@@ -608,6 +651,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
if (requiredTaskCount > 0) {
|
||||
addView(mClearAllButton);
|
||||
showActionsView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +660,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
|
||||
final Task task = tasks.get(i);
|
||||
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
||||
taskView.bind(task);
|
||||
taskView.bind(task, mLayoutRotation);
|
||||
}
|
||||
|
||||
if (mNextPage == INVALID_PAGE) {
|
||||
@@ -647,6 +691,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (indexOfChild(mClearAllButton) != -1) {
|
||||
removeView(mClearAllButton);
|
||||
}
|
||||
hideActionsView();
|
||||
}
|
||||
|
||||
public int getTaskViewCount() {
|
||||
@@ -748,19 +793,21 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
|
||||
return;
|
||||
}
|
||||
int scrollX = getScrollX();
|
||||
final int halfPageWidth = getNormalChildWidth() / 2;
|
||||
final int screenCenter = mInsets.left + getPaddingLeft() + scrollX + halfPageWidth;
|
||||
final int halfScreenWidth = getMeasuredWidth() / 2;
|
||||
CurveProperties curveProperties = mOrientationHandler
|
||||
.getCurveProperties(this, mInsets);
|
||||
int scroll = curveProperties.scroll;
|
||||
final int halfPageSize = curveProperties.halfPageSize;
|
||||
final int screenCenter = curveProperties.screenCenter;
|
||||
final int halfScreenSize = curveProperties.halfScreenSize;
|
||||
final int pageSpacing = mPageSpacing;
|
||||
mScrollState.scrollFromEdge = mIsRtl ? scrollX : (mMaxScrollX - scrollX);
|
||||
mScrollState.scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
|
||||
|
||||
final int pageCount = getPageCount();
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
View page = getPageAt(i);
|
||||
float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth;
|
||||
float pageCenter = mOrientationHandler.getViewCenterPosition(page) + halfPageSize;
|
||||
float distanceFromScreenCenter = screenCenter - pageCenter;
|
||||
float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
|
||||
float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
|
||||
mScrollState.linearInterpolation = Math.min(1,
|
||||
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
|
||||
((PageCallbacks) page).onPageScroll(mScrollState);
|
||||
@@ -892,6 +939,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
setEnableDrawingLiveTile(false);
|
||||
setRunningTaskHidden(true);
|
||||
setRunningTaskIconScaledDown(true);
|
||||
mGestureRunning = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,6 +956,47 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
setSwipeDownShouldLaunchApp(true);
|
||||
}
|
||||
|
||||
private void animateRecentsRotationInPlace(int newRotation) {
|
||||
if (!supportsVerticalLandscape()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AnimatorSet pa = setRecentsChangedOrientation(true);
|
||||
pa.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
updateLayoutRotation(newRotation);
|
||||
((DragLayer)mActivity.getDragLayer()).recreateControllers();
|
||||
rotateAllChildTasks();
|
||||
setRecentsChangedOrientation(false).start();
|
||||
}
|
||||
});
|
||||
pa.start();
|
||||
}
|
||||
|
||||
public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
|
||||
getRunningTaskIndex();
|
||||
int runningIndex = getCurrentPage();
|
||||
AnimatorSet as = new AnimatorSet();
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
if (runningIndex == i) {
|
||||
continue;
|
||||
}
|
||||
View taskView = getTaskViewAt(i);
|
||||
as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
|
||||
}
|
||||
return as;
|
||||
}
|
||||
|
||||
abstract protected boolean supportsVerticalLandscape();
|
||||
|
||||
private void rotateAllChildTasks() {
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
taskView.setOverviewRotation(mLayoutRotation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a gesture from an app has finished.
|
||||
*/
|
||||
@@ -920,6 +1009,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
setRunningTaskHidden(false);
|
||||
animateUpRunningTaskIconScale();
|
||||
mGestureRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -936,6 +1026,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
addView(taskView, mTaskViewStartIndex);
|
||||
if (wasEmpty) {
|
||||
addView(mClearAllButton);
|
||||
showActionsView();
|
||||
}
|
||||
// The temporary running task is only used for the duration between the start of the
|
||||
// gesture and the task list is loaded and applied
|
||||
@@ -943,7 +1034,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
|
||||
false, true, false, false, new ActivityManager.TaskDescription(), 0,
|
||||
new ComponentName("", ""), false);
|
||||
taskView.bind(mTmpRunningTask);
|
||||
taskView.bind(mTmpRunningTask, mLayoutRotation);
|
||||
}
|
||||
|
||||
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
||||
@@ -1119,15 +1210,22 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
|
||||
FloatProperty<View> secondaryViewTranslate =
|
||||
mOrientationHandler.getSecondaryViewTranslate();
|
||||
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
|
||||
int verticalFactor = mOrientationHandler.getTaskDismissDirectionFactor();
|
||||
if (UNSTABLE_SPRINGS.get() && taskView instanceof TaskView) {
|
||||
addAnim(new SpringObjectAnimator<>(taskView, VIEW_TRANSLATE_Y,
|
||||
MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
|
||||
SpringForce.STIFFNESS_MEDIUM,
|
||||
0, -taskView.getHeight()),
|
||||
ResourceProvider rp = DynamicResource.provider(mActivity);
|
||||
float dampingRatio = rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio);
|
||||
float stiffness = rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness);
|
||||
|
||||
addAnim(new SpringObjectAnimator<>(taskView, secondaryViewTranslate,
|
||||
MIN_VISIBLE_CHANGE_PIXELS, dampingRatio,
|
||||
stiffness, 0, verticalFactor * secondaryTaskDimension),
|
||||
duration, LINEAR, anim);
|
||||
} else {
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
|
||||
duration, LINEAR, anim);
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
|
||||
verticalFactor * secondaryTaskDimension), duration, LINEAR, anim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1158,11 +1256,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
int[] oldScroll = new int[count];
|
||||
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
||||
|
||||
int[] newScroll = new int[count];
|
||||
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
||||
getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
|
||||
|
||||
int taskCount = getTaskViewCount();
|
||||
int scrollDiffPerPage = 0;
|
||||
if (count > 1) {
|
||||
@@ -1200,13 +1296,17 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
|
||||
if (scrollDiff != 0) {
|
||||
if (UNSTABLE_SPRINGS.get() && child instanceof TaskView) {
|
||||
ResourceProvider rp = DynamicResource.provider(mActivity);
|
||||
float damping = rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio);
|
||||
float stiffness = rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness);
|
||||
|
||||
addAnim(new SpringObjectAnimator<>(child, VIEW_TRANSLATE_X,
|
||||
MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
|
||||
SpringForce.STIFFNESS_MEDIUM,
|
||||
0, scrollDiff), duration, ACCEL, anim);
|
||||
MIN_VISIBLE_CHANGE_PIXELS, damping,
|
||||
stiffness, 0, scrollDiff), duration, ACCEL, anim);
|
||||
} else {
|
||||
addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff), duration,
|
||||
ACCEL, anim);
|
||||
Property translationProperty = mOrientationHandler.getPrimaryViewTranslate();
|
||||
addAnim(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff),
|
||||
duration, ACCEL, anim);
|
||||
}
|
||||
|
||||
needsCurveUpdates = true;
|
||||
@@ -1252,6 +1352,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
if (getTaskViewCount() == 0) {
|
||||
removeView(mClearAllButton);
|
||||
hideActionsView();
|
||||
startHome();
|
||||
} else {
|
||||
snapToPageImmediately(pageToSnapTo);
|
||||
@@ -1396,15 +1497,17 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
}
|
||||
mClearAllButton.setContentAlpha(mContentAlpha);
|
||||
|
||||
int alphaInt = Math.round(alpha * 255);
|
||||
mEmptyMessagePaint.setAlpha(alphaInt);
|
||||
mEmptyIcon.setAlpha(alphaInt);
|
||||
|
||||
if (alpha > 0) {
|
||||
setVisibility(VISIBLE);
|
||||
if (!mGestureRunning) {
|
||||
showActionsView();
|
||||
}
|
||||
} else if (!mFreezeViewVisibility) {
|
||||
setVisibility(GONE);
|
||||
hideActionsView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1418,10 +1521,27 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
if (!mFreezeViewVisibility) {
|
||||
setVisibility(mContentAlpha > 0 ? VISIBLE : GONE);
|
||||
if (mContentAlpha > 0) {
|
||||
showActionsView();
|
||||
} else {
|
||||
hideActionsView();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutRotation(int touchRotation, int displayRotation) {
|
||||
if (!sFlagForcedRotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.setLayoutRotation(touchRotation, displayRotation);
|
||||
mClearAllButton.onLayoutChanged();
|
||||
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
|
||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAdded(View child) {
|
||||
super.onViewAdded(child);
|
||||
@@ -1642,7 +1762,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
});
|
||||
|
||||
AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(mActivity);
|
||||
AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(
|
||||
getPagedViewOrientedState(), mActivity);
|
||||
appWindowAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this);
|
||||
appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
|
||||
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
|
||||
@@ -1799,7 +1920,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMinScrollX() {
|
||||
protected int computeMinScroll() {
|
||||
if (getTaskViewCount() > 0) {
|
||||
if (mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button,
|
||||
@@ -1814,11 +1935,11 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
return getScrollForPage(mTaskViewStartIndex);
|
||||
}
|
||||
return super.computeMinScrollX();
|
||||
return super.computeMinScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMaxScrollX() {
|
||||
protected int computeMaxScroll() {
|
||||
if (getTaskViewCount() > 0) {
|
||||
if (mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button,
|
||||
@@ -1833,7 +1954,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
|
||||
}
|
||||
return super.computeMaxScrollX();
|
||||
return super.computeMaxScroll();
|
||||
}
|
||||
|
||||
public ClearAllButton getClearAllButton() {
|
||||
@@ -1848,31 +1969,30 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return 0;
|
||||
}
|
||||
int startScroll = getScrollForPage(getRunningTaskIndex());
|
||||
int offsetX = startScroll - getScrollX();
|
||||
offsetX *= getScaleX();
|
||||
int offsetX = startScroll - mOrientationHandler.getPrimaryScroll(this);
|
||||
offsetX *= mOrientationHandler.getPrimaryScale(this);
|
||||
return offsetX;
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
public Consumer<MotionEvent> getEventDispatcher(RotationMode navBarRotationMode) {
|
||||
float degreesRotated;
|
||||
if (navBarRotationMode == RotationMode.NORMAL) {
|
||||
degreesRotated = RotationHelper.getDegreesFromRotation(mLayoutRotation);
|
||||
} else {
|
||||
degreesRotated = -navBarRotationMode.surfaceRotation;
|
||||
}
|
||||
if (degreesRotated == 0) {
|
||||
return super::onTouchEvent;
|
||||
}
|
||||
|
||||
// At this point the event coordinates have already been transformed, so we need to
|
||||
// undo that transformation since PagedView also accommodates for the transformation via
|
||||
// PagedOrientationHandler
|
||||
return e -> {
|
||||
RotationHelper.transformEvent(-degreesRotated, e, true);
|
||||
super.onTouchEvent(e);
|
||||
RotationHelper.transformEvent(-degreesRotated, e, false);
|
||||
};
|
||||
}
|
||||
|
||||
public AppWindowAnimationHelper getClipAnimationHelper() {
|
||||
@@ -1955,4 +2075,51 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
/** @param isEmpty Whether RecentsView is empty (i.e. has no children) */
|
||||
void onEmptyMessageUpdated(boolean isEmpty);
|
||||
}
|
||||
|
||||
|
||||
private static class PinnedStackAnimationListener<T extends BaseActivity> extends
|
||||
IPinnedStackAnimationListener.Stub {
|
||||
private T mActivity;
|
||||
|
||||
public void setActivity(T activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPinnedStackAnimationStarted() {
|
||||
// Needed for activities that auto-enter PiP, which will not trigger a remote
|
||||
// animation to be created
|
||||
mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
|
||||
}
|
||||
}
|
||||
|
||||
private void showActionsView() {
|
||||
if (mActionsView != null && getTaskViewCount() > 0) {
|
||||
mActionsView.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideActionsView() {
|
||||
if (mActionsView != null) {
|
||||
mActionsView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void addActionsView() {
|
||||
if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get()
|
||||
&& SysUINavigationMode.removeShelfFromOverview(mActivity)) {
|
||||
mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view);
|
||||
if (mActionsView != null) {
|
||||
Rect rect = new Rect();
|
||||
getTaskSize(rect);
|
||||
InsettableFrameLayout.LayoutParams layoutParams =
|
||||
new InsettableFrameLayout.LayoutParams(rect.width(),
|
||||
getResources().getDimensionPixelSize(
|
||||
R.dimen.overview_actions_height));
|
||||
layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||
mActionsView.setLayoutParams(layoutParams);
|
||||
showActionsView();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.util.Property;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static android.view.Gravity.BOTTOM;
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import static android.view.Gravity.CENTER_VERTICAL;
|
||||
import static android.view.Gravity.END;
|
||||
import static android.view.Gravity.START;
|
||||
import static android.view.Gravity.TOP;
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
|
||||
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
|
||||
@@ -23,7 +29,6 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -41,25 +46,24 @@ import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
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.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
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;
|
||||
@@ -166,8 +170,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private final float mWindowCornerRadius;
|
||||
private final BaseDraggingActivity mActivity;
|
||||
|
||||
@Nullable private View mActionsView;
|
||||
|
||||
private ObjectAnimator mIconAndDimAnimator;
|
||||
private float mIconScaleAnimStartProgress = 0;
|
||||
private float mFocusTransitionProgress = 1;
|
||||
@@ -237,18 +239,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
||||
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
|
||||
mSnapshotView.setLayoutParams(thumbnailParams);
|
||||
}
|
||||
|
||||
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
|
||||
mActionsView = mSnapshotView.getTaskOverlay().getActionsView();
|
||||
if (mActionsView != null) {
|
||||
TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
|
||||
getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
|
||||
Gravity.BOTTOM);
|
||||
addView(mActionsView, params);
|
||||
mActionsView.setAlpha(0);
|
||||
}
|
||||
}
|
||||
public boolean isTaskOverlayModal() {
|
||||
return mSnapshotView.getTaskOverlay().isOverlayModal();
|
||||
}
|
||||
|
||||
public TaskMenuView getMenuView() {
|
||||
@@ -262,10 +256,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
/**
|
||||
* Updates this task view to the given {@param task}.
|
||||
*/
|
||||
public void bind(Task task) {
|
||||
public void bind(Task task, int recentsRotation) {
|
||||
cancelPendingLoadTasks();
|
||||
mTask = task;
|
||||
mSnapshotView.bind(task);
|
||||
setOverviewRotation(recentsRotation);
|
||||
}
|
||||
|
||||
public Task getTask() {
|
||||
@@ -435,6 +430,42 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
}
|
||||
}
|
||||
|
||||
void setOverviewRotation(int iconRotation) {
|
||||
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
|
||||
boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
|
||||
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
||||
snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext());
|
||||
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
|
||||
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
|
||||
int rotation = RotationHelper.getDegreesFromRotation(iconRotation);
|
||||
switch (iconRotation) {
|
||||
case Surface.ROTATION_90:
|
||||
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
|
||||
iconParams.rightMargin = -thumbnailPadding;
|
||||
iconParams.leftMargin = iconParams.topMargin = iconParams.bottomMargin = 0;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
iconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
|
||||
iconParams.bottomMargin = -thumbnailPadding;
|
||||
iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin = 0;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
|
||||
iconParams.leftMargin = -thumbnailPadding;
|
||||
iconParams.rightMargin = iconParams.topMargin = iconParams.bottomMargin = 0;
|
||||
break;
|
||||
case Surface.ROTATION_0:
|
||||
default:
|
||||
iconParams.gravity = TOP | CENTER_HORIZONTAL;
|
||||
iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin =
|
||||
iconParams.bottomMargin = 0;
|
||||
break;
|
||||
}
|
||||
mSnapshotView.setLayoutParams(snapshotParams);
|
||||
mIconView.setLayoutParams(iconParams);
|
||||
mIconView.setRotation(rotation);
|
||||
}
|
||||
|
||||
private void setIconAndDimTransitionProgress(float progress, boolean invert) {
|
||||
if (invert) {
|
||||
progress = 1 - progress;
|
||||
@@ -449,11 +480,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mIconView.setScaleX(scale);
|
||||
mIconView.setScaleY(scale);
|
||||
|
||||
|
||||
if (mActionsView != null && isRunningTask()) {
|
||||
mActionsView.setAlpha(scale);
|
||||
}
|
||||
|
||||
mFooterVerticalOffset = 1.0f - scale;
|
||||
for (FooterWrapper footer : mFooters) {
|
||||
if (footer != null) {
|
||||
@@ -544,31 +570,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mMenuView.setScaleX(getScaleX());
|
||||
mMenuView.setScaleY(getScaleY());
|
||||
}
|
||||
|
||||
// This is not the proper implementation and will be replaced with a proper layout.
|
||||
if (mActionsView != null) {
|
||||
if (mFocusTransitionProgress == 1f) {
|
||||
mActionsView.setAlpha(1 - curveInterpolation / MAX_PAGE_SCRIM_ALPHA);
|
||||
}
|
||||
maintainActionViewPosition(curveScaleForCurveInterpolation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void maintainActionViewPosition(float curveScaleForCurveInterpolation) {
|
||||
float inverseCurveScaleFactor = curveScaleForCurveInterpolation == 0 ? 0 :
|
||||
(1f / curveScaleForCurveInterpolation);
|
||||
mActionsView.setScaleX(inverseCurveScaleFactor);
|
||||
mActionsView.setScaleY(inverseCurveScaleFactor);
|
||||
mActionsView.setTranslationX(inverseCurveScaleFactor * (-getX()
|
||||
+ getRecentsView().getScrollX() + getRecentsView().scrollOffsetLeft()));
|
||||
mActionsView.setTranslationY(
|
||||
(1f - curveScaleForCurveInterpolation) * (mSnapshotView.getHeight()
|
||||
+ mActionsView.getHeight()) / 2f
|
||||
+ inverseCurveScaleFactor * (-getTranslationY()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the footer at the specific index and returns the previously set footer.
|
||||
*/
|
||||
@@ -597,8 +600,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
|
||||
addView(view, indexToAdd);
|
||||
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
|
||||
layoutParams.gravity =
|
||||
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||
layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL;
|
||||
layoutParams.bottomMargin =
|
||||
((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin;
|
||||
view.setAlpha(mFooterAlpha);
|
||||
@@ -851,9 +853,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mFullscreenProgress = progress;
|
||||
boolean isFullscreen = mFullscreenProgress > 0;
|
||||
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
||||
if (mActionsView != null) {
|
||||
mActionsView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
||||
}
|
||||
setClipChildren(!isFullscreen);
|
||||
setClipToPadding(!isFullscreen);
|
||||
|
||||
@@ -934,5 +933,4 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mScale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/task_thumbnail_icon_size"
|
||||
android:layout_height="@dimen/task_thumbnail_icon_size"
|
||||
android:layout_gravity="top|center_horizontal"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"/>
|
||||
</com.android.quickstep.views.TaskView>
|
||||
@@ -66,27 +66,32 @@
|
||||
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
|
||||
<string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
|
||||
|
||||
|
||||
<!-- Hotseat migration notification title -->
|
||||
<string translatable="false" name="hotseat_migrate_prompt_title">Easily access your most-used apps</string>
|
||||
<string translatable="false" name="hotseat_edu_prompt_title">Get app suggestions based on your routines</string>
|
||||
<!-- Hotseat migration notification content -->
|
||||
<string translatable="false" name="hotseat_migrate_prompt_content">Pixel suggests your favorite apps based on your routines. Tap to learn more.</string>
|
||||
<!-- Hotseat migration wizard title -->
|
||||
<string translatable="false" name="hotseat_migrate_title">Suggested apps replace the bottom row of apps</string>
|
||||
<!-- Hotseat migration wizard message -->
|
||||
<string translatable="false" name="hotseat_migrate_message">Your current apps will move to the last screen. To pin or block a suggested app, drag it off the bottom row.</string>
|
||||
<string translatable="false" name="hotseat_edu_prompt_content">Tap to set up</string>
|
||||
|
||||
|
||||
<!-- Hotseat educational strings for users who don't qualify for migration -->
|
||||
<string translatable="false" name="hotseat_edu_title_migrate">Suggested apps replace the bottom row of apps</string>
|
||||
<string translatable="false" name="hotseat_edu_message_migrate">Your hotseat items will be moved up on the homescreen</string>
|
||||
<string translatable="false" name="hotseat_edu_message_migrate_alt">Your hotseat items will be moved to the last page of your workspace</string>
|
||||
|
||||
|
||||
<!-- Hotseat educational strings for users who don't qualify -->
|
||||
<string translatable="false" name="hotseat_edu_title_no_migrate">Suggested apps will be found at the bottom row of your home screen</string>
|
||||
<string translatable="false" name="hotseat_edu_message_no_migrate">Drag one or many apps off the bottom row of home screen to see app suggestions</string>
|
||||
|
||||
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
|
||||
<string translatable="false" name="hotseat_items_migrated">Bottom row of apps moved to last screen</string>
|
||||
<string translatable="false" name="hotseat_items_migrated">Bottom row of apps moved up.</string>
|
||||
<string translatable="false" name="hotseat_items_migrated_alt">Bottom row of apps moved to last page.</string>
|
||||
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
|
||||
<string translatable="false" name="hotseat_no_migration">Bottom row won\'t be replaced. Manually drag apps for predictions.</string>
|
||||
<!-- Button text to opt in for fully predicted hotseat -->
|
||||
<string translatable="false" name="hotseat_migrate_accept">Turn On</string>
|
||||
<string translatable="false" name="hotseat_edu_accept">Got it</string>
|
||||
<!-- Button text to dismiss opt in for fully predicted hotseat -->
|
||||
<string translatable="false" name="hotseat_migrate_dismiss">No thanks</string>
|
||||
<!-- Hotseat onboard notification title -->
|
||||
<string translatable="false" name="hotseat_onboard_notification_title">Your hotseat just got smarter</string>
|
||||
<!-- Hotseat onboard notification detail -->
|
||||
<string translatable="false" name="hotseat_onboard_notification_detail">Tap here to set it up</string>
|
||||
|
||||
<string translatable="false" name="hotseat_edu_dismiss">No thanks</string>
|
||||
|
||||
|
||||
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
|
||||
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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 com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class OrientationTouchTransformerTest {
|
||||
private static final int SIZE_WIDTH = 1080;
|
||||
private static final int SIZE_HEIGHT = 2280;
|
||||
private static final float DENSITY_DISPLAY_METRICS = 3.0f;
|
||||
|
||||
private OrientationTouchTransformer mTouchTransformer;
|
||||
|
||||
Resources mResources;
|
||||
private DefaultDisplay.Info mInfo;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mResources = mock(Resources.class);
|
||||
when(mResources.getBoolean(anyInt())).thenReturn(true);
|
||||
when(mResources.getDimension(anyInt())).thenReturn(10.0f);
|
||||
DisplayMetrics mockDisplayMetrics = new DisplayMetrics();
|
||||
mockDisplayMetrics.density = DENSITY_DISPLAY_METRICS;
|
||||
when(mResources.getDisplayMetrics()).thenReturn(mockDisplayMetrics);
|
||||
mInfo = createDisplayInfo(Surface.ROTATION_0);
|
||||
mTouchTransformer = new OrientationTouchTransformer(mResources, NO_BUTTON, () -> 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabledMultipeRegions_shouldOverrideFirstRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
DefaultDisplay.Info info2 = createDisplayInfo(Surface.ROTATION_90);
|
||||
mTouchTransformer.createOrAddTouchRegion(info2);
|
||||
|
||||
float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
|
||||
MotionEvent inOldRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inOldRegion);
|
||||
assertFalse(mTouchTransformer.touchInValidSwipeRegions(inOldRegion.getX(), inOldRegion.getY()));
|
||||
|
||||
// Override region
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
inOldRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inOldRegion);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inOldRegion.getX(), inOldRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowMultipeRegions_shouldOverrideFirstRegion() {
|
||||
DefaultDisplay.Info info2 = createDisplayInfo(Surface.ROTATION_90);
|
||||
mTouchTransformer.createOrAddTouchRegion(info2);
|
||||
// We have to add 0 rotation second so that gets set as the current rotation, otherwise
|
||||
// matrix transform will fail (tests only work in Portrait at the moment)
|
||||
mTouchTransformer.enableMultipleRegions(true, mInfo);
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
|
||||
float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
|
||||
MotionEvent inNewRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inNewRegion);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inNewRegion.getX(), inNewRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTransform_taskNotFrozen_notInRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
MotionEvent outOfRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, 100);
|
||||
mTouchTransformer.transform(outOfRegion);
|
||||
assertFalse(mTouchTransformer.touchInValidSwipeRegions(outOfRegion.getX(), outOfRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTransform_taskFrozen_noRotate_outOfRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
mTouchTransformer.enableMultipleRegions(true, mInfo);
|
||||
MotionEvent outOfRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, 100);
|
||||
mTouchTransformer.transform(outOfRegion);
|
||||
assertFalse(mTouchTransformer.touchInValidSwipeRegions(outOfRegion.getX(), outOfRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTransform_taskFrozen_noRotate_inRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
mTouchTransformer.enableMultipleRegions(true, mInfo);
|
||||
float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
|
||||
MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inRegion);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTransform_taskNotFrozen_noRotate_inDefaultRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
|
||||
MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inRegion);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTransform_taskNotFrozen_90Rotate_inRegion() {
|
||||
mTouchTransformer.createOrAddTouchRegion(createDisplayInfo(Surface.ROTATION_90));
|
||||
float y = generateTouchRegionHeight(Surface.ROTATION_90) + 1;
|
||||
MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
|
||||
mTouchTransformer.transform(inRegion);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("There's too much that goes into needing to mock a real motion event so the "
|
||||
+ "transforms in native code get applied correctly. Once that happens then maybe we can"
|
||||
+ " write slightly more complex unit tests")
|
||||
public void applyTransform_taskNotFrozen_90Rotate_inTwoRegions() {
|
||||
mTouchTransformer.createOrAddTouchRegion(mInfo);
|
||||
mTouchTransformer.enableMultipleRegions(true, mInfo);
|
||||
mTouchTransformer.createOrAddTouchRegion(createDisplayInfo(Surface.ROTATION_90));
|
||||
// Landscape point
|
||||
float y1 = generateTouchRegionHeight(Surface.ROTATION_90) + 1;
|
||||
MotionEvent inRegion1_down = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, y1);
|
||||
MotionEvent inRegion1_up = generateMotionEvent(MotionEvent.ACTION_UP, 10, y1);
|
||||
// Portrait point in landscape orientation axis
|
||||
MotionEvent inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 10);
|
||||
mTouchTransformer.transform(inRegion1_down);
|
||||
mTouchTransformer.transform(inRegion2);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion1_down.getX(), inRegion1_down.getY()));
|
||||
// We only process one gesture region until we see a MotionEvent.ACTION_UP
|
||||
assertFalse(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
|
||||
|
||||
mTouchTransformer.transform(inRegion1_up);
|
||||
|
||||
// Set the new region with this MotionEvent.ACTION_DOWN
|
||||
inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 370);
|
||||
mTouchTransformer.transform(inRegion2);
|
||||
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
|
||||
}
|
||||
|
||||
private DefaultDisplay.Info createDisplayInfo(int rotation) {
|
||||
Point p = new Point(SIZE_WIDTH, SIZE_HEIGHT);
|
||||
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
|
||||
p = new Point(SIZE_HEIGHT, SIZE_WIDTH);
|
||||
}
|
||||
return new DefaultDisplay.Info(0, rotation, 0, p, p, p, null);
|
||||
}
|
||||
|
||||
private float generateTouchRegionHeight(int rotation) {
|
||||
float height = SIZE_HEIGHT;
|
||||
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
|
||||
height = SIZE_WIDTH;
|
||||
}
|
||||
return height - ResourceUtils.DEFAULT_NAVBAR_VALUE * DENSITY_DISPLAY_METRICS;
|
||||
}
|
||||
|
||||
private MotionEvent generateMotionEvent(int motionAction, float x, float y) {
|
||||
return MotionEvent.obtain(0, 0, motionAction, x, y, 0);
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,13 @@ import android.os.CancellationSignal;
|
||||
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
import com.android.launcher3.accessibility.SystemActions;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.WellbeingModel;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.proxy.ProxyActivityStarter;
|
||||
import com.android.launcher3.proxy.StartActivityParams;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.BackButtonAlphaHandler;
|
||||
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
@@ -51,6 +53,7 @@ import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
@@ -61,6 +64,8 @@ import java.util.stream.Stream;
|
||||
public abstract class BaseQuickstepLauncher extends Launcher
|
||||
implements NavigationModeChangeListener {
|
||||
|
||||
protected SystemActions mSystemActions;
|
||||
|
||||
/**
|
||||
* Reusable command for applying the back button alpha on the background thread.
|
||||
*/
|
||||
@@ -73,6 +78,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mSystemActions = new SystemActions(this);
|
||||
|
||||
SysUINavigationMode.Mode mode = SysUINavigationMode.INSTANCE.get(this)
|
||||
.addModeChangeListener(this);
|
||||
@@ -130,6 +136,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
getRotationHelper().setRotationHadDifferentUI(newMode != Mode.NO_BUTTON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
mSystemActions.onActivityResult(requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnterAnimationComplete() {
|
||||
super.onEnterAnimationComplete();
|
||||
@@ -193,6 +205,15 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
// removes the task itself.
|
||||
startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
|
||||
}
|
||||
|
||||
// Register all system actions once they are available
|
||||
mSystemActions.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mSystemActions.unregister();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,7 +222,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
|
||||
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
||||
getOverviewPanelContainer().bringToFront();
|
||||
getOverviewPanel().bringToFront();
|
||||
if (getActionsView() != null) {
|
||||
getActionsView().bringToFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,9 +241,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
@Override
|
||||
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
|
||||
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
|
||||
float offscreenTranslationX = getDeviceProfile().widthPx
|
||||
- getOverviewPanel().getPaddingStart();
|
||||
return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
|
||||
PagedOrientationHandler layoutVertical =
|
||||
((RecentsView)getOverviewPanel()).getPagedViewOrientedState().getOrientationHandler();
|
||||
return layoutVertical.getScaleAndTranslation(getDeviceProfile(),
|
||||
getOverviewPanel());
|
||||
}
|
||||
return super.getOverviewScaleAndTranslationForNormalState();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.accessibility;
|
||||
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* Manages the launcher system actions presented to accessibility services.
|
||||
*/
|
||||
public class SystemActions {
|
||||
|
||||
/**
|
||||
* System Action ID to show all apps. This ID should follow the ones in
|
||||
* com.android.systemui.accessibility.SystemActions.
|
||||
*/
|
||||
private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
|
||||
|
||||
private Launcher mLauncher;
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
private RemoteAction mAllAppsAction;
|
||||
private boolean mRegistered;
|
||||
|
||||
public SystemActions(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mAccessibilityManager = (AccessibilityManager) launcher.getSystemService(
|
||||
Context.ACCESSIBILITY_SERVICE);
|
||||
mAllAppsAction = new RemoteAction(
|
||||
Icon.createWithResource(launcher, R.drawable.ic_apps),
|
||||
launcher.getString(R.string.all_apps_label),
|
||||
launcher.getString(R.string.all_apps_label),
|
||||
launcher.createPendingResult(SYSTEM_ACTION_ID_ALL_APPS, new Intent(),
|
||||
0 /* flags */));
|
||||
}
|
||||
|
||||
public void register() {
|
||||
if (mRegistered) {
|
||||
return;
|
||||
}
|
||||
mAccessibilityManager.registerSystemAction(mAllAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
|
||||
mRegistered = true;
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
if (!mRegistered) {
|
||||
return;
|
||||
}
|
||||
mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
|
||||
mRegistered = false;
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode) {
|
||||
if (requestCode == SYSTEM_ACTION_ID_ALL_APPS) {
|
||||
showAllApps();
|
||||
}
|
||||
}
|
||||
|
||||
private void showAllApps() {
|
||||
LauncherStateManager stateManager = mLauncher.getStateManager();
|
||||
stateManager.goToState(NORMAL);
|
||||
stateManager.goToState(ALL_APPS);
|
||||
}
|
||||
}
|
||||
@@ -52,10 +52,12 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
||||
implements StateHandler {
|
||||
protected final T mRecentsView;
|
||||
protected final Launcher mLauncher;
|
||||
protected final View mActionsView;
|
||||
|
||||
public BaseRecentsViewStateController(@NonNull Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mRecentsView = launcher.getOverviewPanel();
|
||||
mActionsView = launcher.getActionsView();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,6 +74,10 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
||||
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
|
||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||
SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
|
||||
if (mActionsView != null) {
|
||||
mActionsView.setTranslationX(translationX);
|
||||
mActionsView.setAlpha(state.overviewUi ? 1f : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,6 +124,11 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
|
||||
builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
|
||||
if (mActionsView != null) {
|
||||
setter.setFloat(mActionsView, View.TRANSLATION_X, translationX, translateXInterpolator);
|
||||
setter.setFloat(mActionsView, View.ALPHA, toState.overviewUi ? 1 : 0,
|
||||
builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
@@ -31,6 +32,7 @@ import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
@@ -49,6 +51,15 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
|
||||
|
||||
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
|
||||
|
||||
/**
|
||||
* @return The progress of the swipe where we start resisting the user, where 0 is fullscreen
|
||||
* and 1 is recents. These values should probably be greater than 1 to let the user swipe past
|
||||
* recents before we start resisting them.
|
||||
*/
|
||||
default Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
|
||||
return new Pair<>(1.4f, 1.8f);
|
||||
}
|
||||
|
||||
void onSwipeUpToRecentsComplete();
|
||||
|
||||
default void onSwipeUpToHomeComplete() { }
|
||||
@@ -148,13 +159,18 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
|
||||
// No-op
|
||||
}
|
||||
|
||||
static RectF getDefaultWindowTargetRect(DeviceProfile dp) {
|
||||
static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
|
||||
DeviceProfile dp) {
|
||||
final int halfIconSize = dp.iconSizePx / 2;
|
||||
final float targetCenterX = dp.availableWidthPx / 2f;
|
||||
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
|
||||
float primaryDimension = orientationHandler
|
||||
.getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
|
||||
float secondaryDimension = orientationHandler
|
||||
.getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
|
||||
final float targetX = primaryDimension / 2f;
|
||||
final float targetY = secondaryDimension - dp.hotseatBarSizePx;
|
||||
// Fallback to animate to center of screen.
|
||||
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
|
||||
targetCenterX + halfIconSize, targetCenterY + halfIconSize);
|
||||
return new RectF(targetX - halfIconSize, targetY - halfIconSize,
|
||||
targetX + halfIconSize, targetY + halfIconSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -281,4 +283,13 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
||||
mStateCallback.setState(STATE_RECENTS_ANIMATION_FINISHED);
|
||||
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("GestureState:");
|
||||
pw.println(" gestureID=" + mGestureId);
|
||||
pw.println(" runningTask=" + mRunningTask);
|
||||
pw.println(" endTarget=" + mEndTarget);
|
||||
pw.println(" finishingRecentsAnimationTaskId=" + mFinishingRecentsAnimationTaskId);
|
||||
pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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_UP;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Maintains state for supporting nav bars and tracking their gestures in multiple orientations.
|
||||
* See {@link OrientationRectF#applyTransform(MotionEvent, boolean)} for transformation of
|
||||
* MotionEvents from one orientation's coordinate space to another's.
|
||||
*
|
||||
* This class only supports single touch/pointer gesture tracking for touches started in a supported
|
||||
* nav bar region.
|
||||
*/
|
||||
class OrientationTouchTransformer {
|
||||
|
||||
private static final String TAG = "OrientationTouchTransformer";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int MAX_ORIENTATIONS = 4;
|
||||
|
||||
private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
|
||||
private final RectF mAssistantLeftRegion = new RectF();
|
||||
private final RectF mAssistantRightRegion = new RectF();
|
||||
private int mCurrentRotation;
|
||||
private boolean mEnableMultipleRegions;
|
||||
private Resources mResources;
|
||||
private OrientationRectF mLastRectTouched;
|
||||
private SysUINavigationMode.Mode mMode;
|
||||
private QuickStepContractInfo mContractInfo;
|
||||
private int mQuickStepStartingRotation = -1;
|
||||
|
||||
/** For testability */
|
||||
interface QuickStepContractInfo {
|
||||
float getWindowCornerRadius();
|
||||
}
|
||||
|
||||
OrientationTouchTransformer(Resources resources, SysUINavigationMode.Mode mode,
|
||||
QuickStepContractInfo contractInfo) {
|
||||
mResources = resources;
|
||||
mMode = mode;
|
||||
mContractInfo = contractInfo;
|
||||
}
|
||||
|
||||
void setNavigationMode(SysUINavigationMode.Mode newMode) {
|
||||
this.mMode = newMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current nav bar region to listen to events for as determined by
|
||||
* {@param info}. If multiple nav bar regions are enabled, then this region will be added
|
||||
* alongside other regions.
|
||||
* Ok to call multiple times
|
||||
*
|
||||
* @see #enableMultipleRegions(boolean, DefaultDisplay.Info)
|
||||
*/
|
||||
void createOrAddTouchRegion(DefaultDisplay.Info info) {
|
||||
mCurrentRotation = info.rotation;
|
||||
if (mQuickStepStartingRotation > -1 && mCurrentRotation == mQuickStepStartingRotation) {
|
||||
// Ignore nav bars in other rotations except for the one we started out in
|
||||
resetSwipeRegions(info);
|
||||
return;
|
||||
}
|
||||
|
||||
OrientationRectF region = mSwipeTouchRegions.get(mCurrentRotation);
|
||||
if (region != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEnableMultipleRegions) {
|
||||
mSwipeTouchRegions.put(mCurrentRotation, createRegionForDisplay(info));
|
||||
} else {
|
||||
resetSwipeRegions(info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when we want to start tracking nav bar touch regions in multiple orientations.
|
||||
* ALSO, you BETTER call this with {@param enableMultipleRegions} set to false once you're done.
|
||||
*
|
||||
* @param enableMultipleRegions Set to true to start tracking multiple nav bar regions
|
||||
* @param info The current displayInfo
|
||||
*/
|
||||
void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) {
|
||||
mEnableMultipleRegions = enableMultipleRegions;
|
||||
if (!enableMultipleRegions) {
|
||||
mQuickStepStartingRotation = -1;
|
||||
resetSwipeRegions(info);
|
||||
} else {
|
||||
if (mQuickStepStartingRotation < 0) {
|
||||
mQuickStepStartingRotation = mLastRectTouched.mRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only saves the swipe region represented by {@param region}, clears the
|
||||
* rest from {@link #mSwipeTouchRegions}
|
||||
* To be called whenever we want to stop tracking more than one swipe region.
|
||||
* Ok to call multiple times.
|
||||
*/
|
||||
private void resetSwipeRegions(DefaultDisplay.Info region) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "clearing all regions except rotation: " + mCurrentRotation);
|
||||
}
|
||||
|
||||
mCurrentRotation = region.rotation;
|
||||
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentRotation);
|
||||
mSwipeTouchRegions.clear();
|
||||
mSwipeTouchRegions.put(mCurrentRotation,
|
||||
regionToKeep != null ? regionToKeep : createRegionForDisplay(region));
|
||||
}
|
||||
|
||||
private OrientationRectF createRegionForDisplay(DefaultDisplay.Info display) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "creating rotation region for: " + mCurrentRotation);
|
||||
}
|
||||
|
||||
Point size = display.realSize;
|
||||
int rotation = display.rotation;
|
||||
OrientationRectF orientationRectF =
|
||||
new OrientationRectF(0, 0, size.x, size.y, rotation);
|
||||
if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
|
||||
int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
|
||||
orientationRectF.top = orientationRectF.bottom - touchHeight;
|
||||
|
||||
final int assistantWidth = mResources
|
||||
.getDimensionPixelSize(R.dimen.gestures_assistant_width);
|
||||
final float assistantHeight = Math.max(touchHeight,
|
||||
mContractInfo.getWindowCornerRadius());
|
||||
mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = orientationRectF.bottom;
|
||||
mAssistantLeftRegion.top = mAssistantRightRegion.top =
|
||||
orientationRectF.bottom - assistantHeight;
|
||||
|
||||
mAssistantLeftRegion.left = 0;
|
||||
mAssistantLeftRegion.right = assistantWidth;
|
||||
|
||||
mAssistantRightRegion.right = orientationRectF.right;
|
||||
mAssistantRightRegion.left = orientationRectF.right - assistantWidth;
|
||||
} else {
|
||||
mAssistantLeftRegion.setEmpty();
|
||||
mAssistantRightRegion.setEmpty();
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
orientationRectF.left = orientationRectF.right
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
orientationRectF.right = orientationRectF.left
|
||||
+ getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
|
||||
break;
|
||||
default:
|
||||
orientationRectF.top = orientationRectF.bottom
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
return orientationRectF;
|
||||
}
|
||||
|
||||
boolean touchInAssistantRegion(MotionEvent ev) {
|
||||
return mAssistantLeftRegion.contains(ev.getX(), ev.getY())
|
||||
|| mAssistantRightRegion.contains(ev.getX(), ev.getY());
|
||||
|
||||
}
|
||||
|
||||
private int getNavbarSize(String resName) {
|
||||
return ResourceUtils.getNavbarSize(resName, mResources);
|
||||
}
|
||||
|
||||
boolean touchInValidSwipeRegions(float x, float y) {
|
||||
if (mLastRectTouched != null) {
|
||||
return mLastRectTouched.contains(x, y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int getCurrentActiveRotation() {
|
||||
if (mLastRectTouched == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return mLastRectTouched.mRotation;
|
||||
}
|
||||
}
|
||||
|
||||
public void transform(MotionEvent event) {
|
||||
int eventAction = event.getActionMasked();
|
||||
switch (eventAction) {
|
||||
case ACTION_MOVE: {
|
||||
if (mLastRectTouched == null) {
|
||||
return;
|
||||
}
|
||||
mLastRectTouched.applyTransform(event, true);
|
||||
break;
|
||||
}
|
||||
case ACTION_CANCEL:
|
||||
case ACTION_UP: {
|
||||
if (mLastRectTouched == null) {
|
||||
return;
|
||||
}
|
||||
mLastRectTouched.applyTransform(event, true);
|
||||
mLastRectTouched = null;
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_DOWN:
|
||||
case ACTION_DOWN: {
|
||||
if (mLastRectTouched != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_ORIENTATIONS; i++) {
|
||||
OrientationRectF rect = mSwipeTouchRegions.get(i);
|
||||
if (rect == null) {
|
||||
continue;
|
||||
}
|
||||
if (rect.applyTransform(event, false)) {
|
||||
mLastRectTouched = rect;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "set active region: " + rect);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("OrientationTouchTransformerState: ");
|
||||
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
|
||||
pw.println(" lastTouchedRegion=" + mLastRectTouched);
|
||||
pw.println(" multipleRegionsEnabled=" + mEnableMultipleRegions);
|
||||
StringBuilder regions = new StringBuilder(" currentTouchableRotations=");
|
||||
for(int i = 0; i < mSwipeTouchRegions.size(); i++) {
|
||||
OrientationRectF rectF = mSwipeTouchRegions.get(mSwipeTouchRegions.keyAt(i));
|
||||
regions.append(rectF.mRotation).append(" ");
|
||||
}
|
||||
pw.println(regions.toString());
|
||||
}
|
||||
|
||||
private class OrientationRectF extends RectF {
|
||||
|
||||
/**
|
||||
* Delta to subtract width and height by because if we report the translated touch
|
||||
* bounds as the width and height, calling {@link RectF#contains(float, float)} will
|
||||
* be false
|
||||
*/
|
||||
private float maxDelta = 0.001f;
|
||||
|
||||
private int mRotation;
|
||||
private float mHeight;
|
||||
private float mWidth;
|
||||
|
||||
OrientationRectF(float left, float top, float right, float bottom, int rotation) {
|
||||
super(left, top, right, bottom);
|
||||
this.mRotation = rotation;
|
||||
mHeight = bottom - maxDelta;
|
||||
mWidth = right - maxDelta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = super.toString();
|
||||
s += " rotation: " + mRotation;
|
||||
return s;
|
||||
}
|
||||
|
||||
boolean applyTransform(MotionEvent event, boolean forceTransform) {
|
||||
// TODO(b/149658423): See if we can use RotationHelper.getRotationMatrix here
|
||||
MotionEvent tmp = MotionEvent.obtain(event);
|
||||
Matrix outMatrix = new Matrix();
|
||||
int delta = RotationHelper.deltaRotation(mCurrentRotation, mRotation);
|
||||
switch (delta) {
|
||||
case Surface.ROTATION_0:
|
||||
outMatrix.reset();
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
outMatrix.setRotate(270);
|
||||
outMatrix.postTranslate(0, mHeight);
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
outMatrix.setRotate(180);
|
||||
outMatrix.postTranslate(mHeight, mWidth);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
outMatrix.setRotate(90);
|
||||
outMatrix.postTranslate(mWidth, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
tmp.transform(outMatrix);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
|
||||
+ " new: " + tmp.getX() + ", " + tmp.getY()
|
||||
+ " rect: " + this + " forceTransform: " + forceTransform
|
||||
+ " contains: " + contains(tmp.getX(), tmp.getY()));
|
||||
}
|
||||
|
||||
if (forceTransform || contains(tmp.getX(), tmp.getY())) {
|
||||
event.transform(outMatrix);
|
||||
tmp.recycle();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -44,18 +45,11 @@ import java.util.Objects;
|
||||
* and provide callers the relevant classes.
|
||||
*/
|
||||
public final class OverviewComponentObserver {
|
||||
private final BroadcastReceiver mUserPreferenceChangeReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateOverviewTargets();
|
||||
}
|
||||
};
|
||||
private final BroadcastReceiver mOtherHomeAppUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateOverviewTargets();
|
||||
}
|
||||
};
|
||||
private final BroadcastReceiver mUserPreferenceChangeReceiver =
|
||||
new SimpleBroadcastReceiver(this::updateOverviewTargets);
|
||||
private final BroadcastReceiver mOtherHomeAppUpdateReceiver =
|
||||
new SimpleBroadcastReceiver(this::updateOverviewTargets);
|
||||
|
||||
private final Context mContext;
|
||||
private final RecentsAnimationDeviceState mDeviceState;
|
||||
private final Intent mCurrentHomeIntent;
|
||||
@@ -106,6 +100,10 @@ public final class OverviewComponentObserver {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOverviewTargets(Intent unused) {
|
||||
updateOverviewTargets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update overview intent and {@link BaseActivityInterface} based off the current launcher home
|
||||
* component.
|
||||
@@ -131,11 +129,8 @@ public final class OverviewComponentObserver {
|
||||
mOverviewIntent = mMyHomeIntent;
|
||||
mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
|
||||
|
||||
if (mUpdateRegisteredPackage != null) {
|
||||
// Remove any update listener as we don't care about other packages.
|
||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
||||
mUpdateRegisteredPackage = null;
|
||||
}
|
||||
// Remove any update listener as we don't care about other packages.
|
||||
unregisterOtherHomeAppUpdateReceiver();
|
||||
} else {
|
||||
// The default home app is a different launcher. Use the fallback Overview instead.
|
||||
|
||||
@@ -149,13 +144,9 @@ public final class OverviewComponentObserver {
|
||||
// Listen for package updates of this app (and remove any previously attached
|
||||
// package listener).
|
||||
if (defaultHome == null) {
|
||||
if (mUpdateRegisteredPackage != null) {
|
||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
||||
}
|
||||
unregisterOtherHomeAppUpdateReceiver();
|
||||
} else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
|
||||
if (mUpdateRegisteredPackage != null) {
|
||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
||||
}
|
||||
unregisterOtherHomeAppUpdateReceiver();
|
||||
|
||||
mUpdateRegisteredPackage = defaultHome.getPackageName();
|
||||
mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter(
|
||||
@@ -170,7 +161,10 @@ public final class OverviewComponentObserver {
|
||||
*/
|
||||
public void onDestroy() {
|
||||
mContext.unregisterReceiver(mUserPreferenceChangeReceiver);
|
||||
unregisterOtherHomeAppUpdateReceiver();
|
||||
}
|
||||
|
||||
private void unregisterOtherHomeAppUpdateReceiver() {
|
||||
if (mUpdateRegisteredPackage != null) {
|
||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
||||
mUpdateRegisteredPackage = null;
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Wrapper around RecentsAnimationController to help with some synchronization
|
||||
* Wrapper around RecentsAnimationControllerCompat to help with some synchronization
|
||||
*/
|
||||
public class RecentsAnimationController {
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ package com.android.quickstep;
|
||||
|
||||
import static android.content.Intent.ACTION_USER_UNLOCKED;
|
||||
|
||||
import static com.android.launcher3.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE;
|
||||
import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||
@@ -40,20 +38,17 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.os.Process;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
@@ -63,6 +58,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -80,6 +76,7 @@ public class RecentsAnimationDeviceState implements
|
||||
private final SysUINavigationMode mSysUiNavMode;
|
||||
private final DefaultDisplay mDefaultDisplay;
|
||||
private final int mDisplayId;
|
||||
private int mDisplayRotation;
|
||||
|
||||
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
||||
|
||||
@@ -87,10 +84,7 @@ public class RecentsAnimationDeviceState implements
|
||||
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
|
||||
private NavBarPosition mNavBarPosition;
|
||||
|
||||
private final RectF mSwipeUpTouchRegion = new RectF();
|
||||
private final Region mDeferredGestureRegion = new Region();
|
||||
private final RectF mAssistantLeftRegion = new RectF();
|
||||
private final RectF mAssistantRightRegion = new RectF();
|
||||
private boolean mAssistantAvailable;
|
||||
private float mAssistantVisibility;
|
||||
|
||||
@@ -106,10 +100,13 @@ public class RecentsAnimationDeviceState implements
|
||||
}
|
||||
};
|
||||
|
||||
private OrientationTouchTransformer mOrientationTouchTransformer;
|
||||
|
||||
private Region mExclusionRegion;
|
||||
private SystemGestureExclusionListenerCompat mExclusionListener;
|
||||
|
||||
private final List<ComponentName> mGestureBlockedActivities;
|
||||
private TaskStackChangeListener mFrozenTaskListener;
|
||||
|
||||
public RecentsAnimationDeviceState(Context context) {
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
@@ -139,6 +136,8 @@ public class RecentsAnimationDeviceState implements
|
||||
};
|
||||
runOnDestroy(mExclusionListener::unregister);
|
||||
|
||||
setupOrientationSwipeHandler(context);
|
||||
|
||||
// Register for navigation mode changes
|
||||
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
||||
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
|
||||
@@ -160,6 +159,26 @@ public class RecentsAnimationDeviceState implements
|
||||
}
|
||||
}
|
||||
|
||||
private void setupOrientationSwipeHandler(Context context) {
|
||||
final Resources resources = context.getResources();
|
||||
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
|
||||
() -> QuickStepContract.getWindowCornerRadius(resources));
|
||||
|
||||
if (!PagedView.sFlagForcedRotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFrozenTaskListener = new TaskStackChangeListener() {
|
||||
@Override
|
||||
public void onRecentTaskListFrozenChanged(boolean frozen) {
|
||||
mOrientationTouchTransformer.enableMultipleRegions(frozen, mDefaultDisplay.getInfo());
|
||||
}
|
||||
};
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
|
||||
runOnDestroy(() -> ActivityManagerWrapper.getInstance()
|
||||
.unregisterTaskStackListener(mFrozenTaskListener));
|
||||
}
|
||||
|
||||
private void runOnDestroy(Runnable action) {
|
||||
mOnDestroyActions.add(action);
|
||||
}
|
||||
@@ -198,7 +217,10 @@ public class RecentsAnimationDeviceState implements
|
||||
mExclusionListener.unregister();
|
||||
}
|
||||
mMode = newMode;
|
||||
|
||||
mNavBarPosition = new NavBarPosition(mMode, mDefaultDisplay.getInfo());
|
||||
|
||||
mOrientationTouchTransformer.setNavigationMode(mMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,8 +229,10 @@ public class RecentsAnimationDeviceState implements
|
||||
return;
|
||||
}
|
||||
|
||||
mDisplayRotation = info.rotation;
|
||||
mNavBarPosition = new NavBarPosition(mMode, info);
|
||||
updateGestureTouchRegions();
|
||||
mOrientationTouchTransformer.createOrAddTouchRegion(info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,50 +404,14 @@ public class RecentsAnimationDeviceState implements
|
||||
return;
|
||||
}
|
||||
|
||||
Resources res = mContext.getResources();
|
||||
DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
|
||||
Point realSize = new Point(displayInfo.realSize);
|
||||
mSwipeUpTouchRegion.set(0, 0, realSize.x, realSize.y);
|
||||
if (mMode == NO_BUTTON) {
|
||||
int touchHeight = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
|
||||
mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom - touchHeight;
|
||||
|
||||
final int assistantWidth = res.getDimensionPixelSize(R.dimen.gestures_assistant_width);
|
||||
final float assistantHeight = Math.max(touchHeight,
|
||||
QuickStepContract.getWindowCornerRadius(res));
|
||||
mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeUpTouchRegion.bottom;
|
||||
mAssistantLeftRegion.top = mAssistantRightRegion.top =
|
||||
mSwipeUpTouchRegion.bottom - assistantHeight;
|
||||
|
||||
mAssistantLeftRegion.left = 0;
|
||||
mAssistantLeftRegion.right = assistantWidth;
|
||||
|
||||
mAssistantRightRegion.right = mSwipeUpTouchRegion.right;
|
||||
mAssistantRightRegion.left = mSwipeUpTouchRegion.right - assistantWidth;
|
||||
} else {
|
||||
mAssistantLeftRegion.setEmpty();
|
||||
mAssistantRightRegion.setEmpty();
|
||||
switch (displayInfo.rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
mSwipeUpTouchRegion.left = mSwipeUpTouchRegion.right
|
||||
- ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
mSwipeUpTouchRegion.right = mSwipeUpTouchRegion.left
|
||||
+ ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
|
||||
break;
|
||||
default:
|
||||
mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom
|
||||
- ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
|
||||
}
|
||||
}
|
||||
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
||||
*/
|
||||
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
|
||||
return mSwipeUpTouchRegion.contains(event.getX(), event.getY());
|
||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,7 +419,8 @@ public class RecentsAnimationDeviceState implements
|
||||
* is in the swipe up gesture region.
|
||||
*/
|
||||
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
|
||||
return mSwipeUpTouchRegion.contains(event.getX(pointerIndex), event.getY(pointerIndex));
|
||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
|
||||
event.getY(pointerIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,11 +479,34 @@ public class RecentsAnimationDeviceState implements
|
||||
public boolean canTriggerAssistantAction(MotionEvent ev) {
|
||||
return mAssistantAvailable
|
||||
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
||||
&& (mAssistantLeftRegion.contains(ev.getX(), ev.getY())
|
||||
|| mAssistantRightRegion.contains(ev.getX(), ev.getY()))
|
||||
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
|
||||
&& !isLockToAppActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* *May* apply a transform on the motion event if it lies in the nav bar region for another
|
||||
* orientation that is currently being tracked as a part of quickstep
|
||||
*/
|
||||
public void setOrientationTransformIfNeeded(MotionEvent event) {
|
||||
// negative coordinates bug b/143901881
|
||||
if (event.getX() < 0 || event.getY() < 0) {
|
||||
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
|
||||
}
|
||||
mOrientationTouchTransformer.transform(event);
|
||||
}
|
||||
|
||||
public void enableMultipleRegions(boolean enable) {
|
||||
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
|
||||
}
|
||||
|
||||
public int getCurrentActiveRotation() {
|
||||
return mOrientationTouchTransformer.getCurrentActiveRotation();
|
||||
}
|
||||
|
||||
public int getDisplayRotation() {
|
||||
return mDisplayRotation;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("DeviceState:");
|
||||
pw.println(" canStartSystemGesture=" + canStartSystemGesture());
|
||||
@@ -504,5 +516,8 @@ public class RecentsAnimationDeviceState implements
|
||||
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
||||
pw.println(" assistantDisabled="
|
||||
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
|
||||
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
|
||||
pw.println(" displayRotation=" + getDisplayRotation());
|
||||
mOrientationTouchTransformer.dump(pw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,4 +333,15 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onQuickSwitchToNewTask() {
|
||||
//TODO(b/150250451) add back in after big CL goes through
|
||||
// if (mSystemUiProxy != null) {
|
||||
// try {
|
||||
// mSystemUiProxy.onQuickSwitchToNewTask();
|
||||
// } catch (RemoteException e) {
|
||||
// Log.w(TAG, "Failed call onQuickstepStarted", e);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ import com.android.quickstep.SysUINavigationMode;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
public class LayoutUtils {
|
||||
|
||||
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
|
||||
|
||||
@@ -11,6 +11,7 @@ import static org.junit.Assert.assertTrue;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -33,6 +34,9 @@ public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
|
||||
|
||||
@Test
|
||||
public void testToast() throws Exception {
|
||||
// b/150303529
|
||||
if (Build.MODEL.contains("Cuttlefish")) return;
|
||||
|
||||
startAppFast(CALCULATOR_PACKAGE);
|
||||
|
||||
final UsageStatsManager usageStatsManager =
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
|
||||
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
|
||||
import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -41,7 +39,6 @@ import com.android.launcher3.tapl.Overview;
|
||||
import com.android.launcher3.tapl.OverviewTask;
|
||||
import com.android.launcher3.tapl.TestHelpers;
|
||||
import com.android.launcher3.ui.TaplTestsLauncher3;
|
||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
@@ -254,8 +251,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
// b/143285809 Remove @Stability on 02/27/20 if the test doesn't flake.
|
||||
@TestStabilityRule.Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT)
|
||||
public void testQuickSwitchFromApp() throws Exception {
|
||||
startTestActivity(2);
|
||||
startTestActivity(3);
|
||||
|
||||
@@ -44,8 +44,13 @@
|
||||
layout="@layout/hotseat" />
|
||||
|
||||
<include
|
||||
android:id="@+id/overview_panel_container"
|
||||
layout="@layout/overview_panel"/>
|
||||
android:id="@+id/overview_panel"
|
||||
layout="@layout/overview_panel"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
android:id="@+id/overview_actions_view"
|
||||
layout="@layout/overview_actions_holder" />
|
||||
|
||||
<!-- Keep these behind the workspace so that they are not visible when
|
||||
we go into AllApps -->
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<Space
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp" />
|
||||
@@ -14,9 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/overview_panel_recents"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone" />
|
||||
<Space
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp" />
|
||||
+53
-1
@@ -121,5 +121,57 @@
|
||||
<bool name="config_enableTaskSnapshotPreloading">true</bool>
|
||||
|
||||
<!-- Configuration resources -->
|
||||
<array name="dynamic_resources"> </array>
|
||||
<item name="all_apps_spring_damping_ratio" type="dimen" format="float">0.75</item>
|
||||
<item name="all_apps_spring_stiffness" type="dimen" format="float">600</item>
|
||||
|
||||
<item name="dismiss_task_trans_y_damping_ratio" type="dimen" format="float">0.5</item>
|
||||
<item name="dismiss_task_trans_y_stiffness" type="dimen" format="float">1500</item>
|
||||
|
||||
<item name="dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.5</item>
|
||||
<item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">1500</item>
|
||||
|
||||
<item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.75</item>
|
||||
<item name="horizontal_spring_stiffness" type="dimen" format="float">200</item>
|
||||
|
||||
<item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
|
||||
<item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
|
||||
|
||||
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
|
||||
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
|
||||
<item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
|
||||
|
||||
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
|
||||
<item name="staggered_stiffness" type="dimen" format="float">150</item>
|
||||
|
||||
<!-- Swipe up to home related -->
|
||||
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
|
||||
<dimen name="swipe_up_y_overshoot">10dp</dimen>
|
||||
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
|
||||
|
||||
<array name="dynamic_resources">
|
||||
<item>@dimen/all_apps_spring_damping_ratio</item>
|
||||
<item>@dimen/all_apps_spring_stiffness</item>
|
||||
|
||||
<item>@dimen/dismiss_task_trans_y_damping_ratio</item>
|
||||
<item>@dimen/dismiss_task_trans_y_stiffness</item>
|
||||
|
||||
<item>@dimen/dismiss_task_trans_x_damping_ratio</item>
|
||||
<item>@dimen/dismiss_task_trans_x_stiffness</item>
|
||||
|
||||
<item>@dimen/horizontal_spring_damping_ratio</item>
|
||||
<item>@dimen/horizontal_spring_stiffness</item>
|
||||
|
||||
<item>@dimen/swipe_up_rect_scale_damping_ratio</item>
|
||||
<item>@dimen/swipe_up_rect_scale_stiffness</item>
|
||||
|
||||
<item>@dimen/swipe_up_rect_xy_fling_friction</item>
|
||||
<item>@dimen/swipe_up_rect_xy_damping_ratio</item>
|
||||
<item>@dimen/swipe_up_rect_xy_stiffness</item>
|
||||
|
||||
<item>@dimen/staggered_damping_ratio</item>
|
||||
<item>@dimen/staggered_stiffness</item>
|
||||
|
||||
<item>@dimen/swipe_up_fling_min_visible_change</item>
|
||||
<item>@dimen/swipe_up_y_overshoot</item>
|
||||
</array>
|
||||
</resources>
|
||||
|
||||
@@ -2783,6 +2783,26 @@ public class CellLayout extends ViewGroup implements Transposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds solution to accept hotseat migration to cell layout. commits solution if commitConfig
|
||||
*/
|
||||
public boolean makeSpaceForHotseatMigration(boolean commitConfig) {
|
||||
if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) return false;
|
||||
int[] cellPoint = new int[2];
|
||||
int[] directionVector = new int[]{0, -1};
|
||||
cellToPoint(0, mCountY, cellPoint);
|
||||
ItemConfiguration configuration = new ItemConfiguration();
|
||||
if (findReorderSolution(cellPoint[0], cellPoint[1], mCountX, 1, mCountX, 1,
|
||||
directionVector, null, false, configuration).isSolution) {
|
||||
if (commitConfig) {
|
||||
copySolutionToTempState(configuration, null);
|
||||
commitTempPlacement();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRegionVacant(int x, int y, int spanX, int spanY) {
|
||||
return mOccupied.isRegionVacant(x, y, spanX, spanY);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -274,7 +273,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
// UI and state for the overview panel
|
||||
private View mOverviewPanel;
|
||||
private FrameLayout mOverviewPanelContainer;
|
||||
private View mActionsView;
|
||||
|
||||
@Thunk
|
||||
boolean mWorkspaceLoading = true;
|
||||
@@ -834,6 +833,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
}
|
||||
}
|
||||
|
||||
mDragLayer.clearAnimatedView();
|
||||
}
|
||||
|
||||
@@ -1162,8 +1162,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
|
||||
mWorkspace = mDragLayer.findViewById(R.id.workspace);
|
||||
mWorkspace.initParentViews(mDragLayer);
|
||||
mOverviewPanel = findViewById(R.id.overview_panel_recents);
|
||||
mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
|
||||
mOverviewPanel = findViewById(R.id.overview_panel);
|
||||
mActionsView = findViewById(R.id.overview_actions_view);
|
||||
mHotseat = findViewById(R.id.hotseat);
|
||||
|
||||
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
@@ -1363,7 +1363,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
protected void onUiChangedWhileSleeping() { }
|
||||
|
||||
public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
||||
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
||||
mWorkspace.updateNotificationDots(updatedDots);
|
||||
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
|
||||
}
|
||||
@@ -1411,8 +1411,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
return (T) mOverviewPanel;
|
||||
}
|
||||
|
||||
public FrameLayout getOverviewPanelContainer() {
|
||||
return mOverviewPanelContainer;
|
||||
public View getActionsView() {
|
||||
return mActionsView;
|
||||
}
|
||||
|
||||
public DropTargetBar getDropTargetBar() {
|
||||
@@ -2327,6 +2327,13 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
|
||||
getModelWriter().updateItemInDatabase(item);
|
||||
}
|
||||
else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
|
||||
&& appWidgetInfo.configure != null) {
|
||||
if (mAppWidgetManager.isAppWidgetRestored(item.appWidgetId)) {
|
||||
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
|
||||
getModelWriter().updateItemInDatabase(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
|
||||
@@ -2340,6 +2347,11 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
item.minSpanX = appWidgetInfo.minSpanX;
|
||||
item.minSpanY = appWidgetInfo.minSpanY;
|
||||
view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
|
||||
} else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
|
||||
&& appWidgetInfo != null) {
|
||||
mAppWidgetHost.addPendingView(item.appWidgetId,
|
||||
new PendingAppWidgetHostView(this, item, mIconCache, false));
|
||||
view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
|
||||
} else {
|
||||
view = new PendingAppWidgetHostView(this, item, mIconCache, false);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.widget.Toast;
|
||||
import com.android.launcher3.model.WidgetsModel;
|
||||
import com.android.launcher3.widget.DeferredAppWidgetHostView;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.PendingAppWidgetHostView;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -53,12 +54,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
|
||||
private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
|
||||
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
|
||||
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
|
||||
|
||||
private final Context mContext;
|
||||
private int mFlags = FLAG_RESUMED;
|
||||
|
||||
private IntConsumer mAppWidgetRemovedCallback = null;
|
||||
|
||||
|
||||
public LauncherAppWidgetHost(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -73,7 +76,13 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
@Override
|
||||
protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
|
||||
AppWidgetProviderInfo appWidget) {
|
||||
LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
|
||||
final LauncherAppWidgetHostView view;
|
||||
if (mPendingViews.get(appWidgetId) != null) {
|
||||
view = mPendingViews.get(appWidgetId);
|
||||
mPendingViews.remove(appWidgetId);
|
||||
} else {
|
||||
view = new LauncherAppWidgetHostView(context);
|
||||
}
|
||||
mViews.put(appWidgetId, view);
|
||||
return view;
|
||||
}
|
||||
@@ -189,6 +198,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
}
|
||||
}
|
||||
|
||||
void addPendingView(int appWidgetId, PendingAppWidgetHostView view) {
|
||||
mPendingViews.put(appWidgetId, view);
|
||||
}
|
||||
|
||||
public AppWidgetHostView createView(Context context, int appWidgetId,
|
||||
LauncherAppWidgetProviderInfo appWidget) {
|
||||
if (appWidget.isCustomWidget()) {
|
||||
@@ -238,8 +251,8 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
|
||||
/**
|
||||
* Called on an appWidget is removed for a widgetId
|
||||
* @param appWidgetId
|
||||
* TODO: make this override when SDK is updated
|
||||
*
|
||||
* @param appWidgetId TODO: make this override when SDK is updated
|
||||
*/
|
||||
public void onAppWidgetRemoved(int appWidgetId) {
|
||||
if (mAppWidgetRemovedCallback == null) {
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -35,6 +30,7 @@ import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
@@ -49,13 +45,26 @@ import android.widget.ScrollView;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.PagedViewOrientedState;
|
||||
import com.android.launcher3.pageindicators.PageIndicator;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.touch.PortraitPagedViewHandler;
|
||||
import com.android.launcher3.touch.OverScroll;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler.ChildBounds;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
|
||||
|
||||
/**
|
||||
* An abstraction of the original Workspace which supports browsing through a
|
||||
* sequential list of "pages"
|
||||
@@ -64,6 +73,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
private static final String TAG = "PagedView";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static boolean sFlagForcedRotation = false;
|
||||
|
||||
public static final int INVALID_PAGE = -1;
|
||||
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
|
||||
|
||||
@@ -97,8 +108,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
protected int mNextPage = INVALID_PAGE;
|
||||
protected int mMinScrollX;
|
||||
protected int mMaxScrollX;
|
||||
protected int mMaxScroll;
|
||||
protected int mMinScroll;
|
||||
protected OverScroller mScroller;
|
||||
private Interpolator mDefaultInterpolator;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
@@ -106,9 +117,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
private float mDownMotionX;
|
||||
private float mDownMotionY;
|
||||
private float mLastMotionX;
|
||||
private float mLastMotionXRemainder;
|
||||
private float mTotalMotionX;
|
||||
private float mDownMotionPrimary;
|
||||
private float mLastMotion;
|
||||
private float mLastMotionRemainder;
|
||||
private float mTotalMotion;
|
||||
protected PagedOrientationHandler mOrientationHandler = new PortraitPagedViewHandler();
|
||||
protected final PagedViewOrientedState mOrientationState = new PagedViewOrientedState();
|
||||
|
||||
protected int[] mPageScrolls;
|
||||
private boolean mIsBeingDragged;
|
||||
@@ -123,11 +137,14 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
protected boolean mIsPageInTransition = false;
|
||||
|
||||
protected float mSpringOverScrollX;
|
||||
protected float mSpringOverScroll;
|
||||
|
||||
protected boolean mWasInOverscroll = false;
|
||||
|
||||
protected int mUnboundedScrollX;
|
||||
protected int mUnboundedScroll;
|
||||
|
||||
protected int mLayoutRotation = Surface.ROTATION_0;
|
||||
protected int mDisplayRotation = Surface.ROTATION_0;
|
||||
|
||||
// Page Indicator
|
||||
@Thunk int mPageIndicatorViewId;
|
||||
@@ -166,11 +183,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
* Initializes various states for this workspace.
|
||||
*/
|
||||
protected void init() {
|
||||
mScroller = new OverScroller(getContext());
|
||||
Context context = getContext();
|
||||
mScroller = new OverScroller(context);
|
||||
setDefaultInterpolator(Interpolators.SCROLL);
|
||||
mCurrentPage = 0;
|
||||
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||
mTouchSlop = configuration.getScaledPagingTouchSlop();
|
||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||
|
||||
@@ -182,6 +200,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
if (Utilities.ATLEAST_OREO) {
|
||||
setDefaultFocusHighlightEnabled(false);
|
||||
}
|
||||
|
||||
sFlagForcedRotation = Utilities.isForcedRotation(context);
|
||||
}
|
||||
|
||||
protected void setDefaultInterpolator(Interpolator interpolator) {
|
||||
@@ -236,12 +256,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
*/
|
||||
protected void updateCurrentPageScroll() {
|
||||
// If the current page is invalid, just reset the scroll position to zero
|
||||
int newX = 0;
|
||||
int newPosition = 0;
|
||||
if (0 <= mCurrentPage && mCurrentPage < getPageCount()) {
|
||||
newX = getScrollForPage(mCurrentPage);
|
||||
newPosition = getScrollForPage(mCurrentPage);
|
||||
}
|
||||
scrollTo(newX, 0);
|
||||
mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
|
||||
mOrientationHandler.set(this, VIEW_SCROLL_TO, newPosition);
|
||||
mOrientationHandler.scrollerStartScroll(mScroller, newPosition);
|
||||
forceFinishScroller(true);
|
||||
}
|
||||
|
||||
@@ -285,7 +305,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
int dir = !mIsRtl ? 1 : - 1;
|
||||
int currScroll = getScrollForPage(page);
|
||||
int prevScroll;
|
||||
while (currScroll < mMinScrollX) {
|
||||
while (currScroll < mMinScroll) {
|
||||
page += dir;
|
||||
prevScroll = currScroll;
|
||||
currScroll = getScrollForPage(page);
|
||||
@@ -294,7 +314,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (currScroll > mMaxScrollX) {
|
||||
while (currScroll > mMaxScroll) {
|
||||
page -= dir;
|
||||
prevScroll = currScroll;
|
||||
currScroll = getScrollForPage(page);
|
||||
@@ -378,45 +398,73 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
|
||||
}
|
||||
|
||||
protected int getUnboundedScrollX() {
|
||||
return mUnboundedScrollX;
|
||||
protected int getUnboundedScroll() {
|
||||
return mUnboundedScroll;
|
||||
}
|
||||
|
||||
protected void updateLayoutRotation(int touchRotation) {
|
||||
setLayoutRotation(touchRotation, mDisplayRotation);
|
||||
}
|
||||
|
||||
/** @param touchRotation Must be one of {@link android.view.Surface.ROTATION_0/90/180/270} */
|
||||
public void setLayoutRotation(int touchRotation, int displayRotation) {
|
||||
if (mLayoutRotation == touchRotation && mDisplayRotation == displayRotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOrientationState.update(touchRotation, displayRotation);
|
||||
mOrientationHandler = mOrientationState.getOrientationHandler();
|
||||
mLayoutRotation = touchRotation;
|
||||
mDisplayRotation = displayRotation;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public PagedViewOrientedState getPagedViewOrientedState() {
|
||||
return mOrientationState;
|
||||
}
|
||||
|
||||
public PagedOrientationHandler getPagedOrientationHandler() {
|
||||
return getPagedViewOrientedState().getOrientationHandler();
|
||||
}
|
||||
|
||||
public void disableMultipleLayoutRotations(boolean disable) {
|
||||
mOrientationState.disableMultipleOrientations(disable);
|
||||
mOrientationHandler = mOrientationState.getOrientationHandler();
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollBy(int x, int y) {
|
||||
scrollTo(getUnboundedScrollX() + x, getScrollY() + y);
|
||||
mOrientationHandler.delegateScrollBy(this, getUnboundedScroll(), x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollTo(int x, int y) {
|
||||
mUnboundedScrollX = x;
|
||||
int primaryScroll = mOrientationHandler.getPrimaryValue(x, y);
|
||||
int secondaryScroll = mOrientationHandler.getSecondaryValue(x, y);
|
||||
mUnboundedScroll = primaryScroll;
|
||||
|
||||
boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < mMinScrollX);
|
||||
boolean isXAfterLastPage = mIsRtl ? (x < mMinScrollX) : (x > mMaxScrollX);
|
||||
|
||||
if (!isXBeforeFirstPage && !isXAfterLastPage) {
|
||||
mSpringOverScrollX = 0;
|
||||
boolean isBeforeFirstPage = mIsRtl ?
|
||||
(primaryScroll > mMaxScroll) : (primaryScroll < mMinScroll);
|
||||
boolean isAfterLastPage = mIsRtl ?
|
||||
(primaryScroll < mMinScroll) : (primaryScroll > mMaxScroll);
|
||||
if (!isBeforeFirstPage && !isAfterLastPage) {
|
||||
mSpringOverScroll = 0;
|
||||
}
|
||||
|
||||
if (isXBeforeFirstPage) {
|
||||
super.scrollTo(mIsRtl ? mMaxScrollX : mMinScrollX, y);
|
||||
if (isBeforeFirstPage) {
|
||||
mOrientationHandler.delegateScrollTo(this,
|
||||
secondaryScroll, mIsRtl ? mMaxScroll : mMinScroll);
|
||||
if (mAllowOverScroll) {
|
||||
mWasInOverscroll = true;
|
||||
if (mIsRtl) {
|
||||
overScroll(x - mMaxScrollX);
|
||||
} else {
|
||||
overScroll(x - mMinScrollX);
|
||||
}
|
||||
overScroll(primaryScroll - (mIsRtl ? mMaxScroll : mMinScroll));
|
||||
}
|
||||
} else if (isXAfterLastPage) {
|
||||
super.scrollTo(mIsRtl ? mMinScrollX : mMaxScrollX, y);
|
||||
} else if (isAfterLastPage) {
|
||||
mOrientationHandler.delegateScrollTo(this,
|
||||
secondaryScroll, mIsRtl ? mMinScroll : mMaxScroll);
|
||||
if (mAllowOverScroll) {
|
||||
mWasInOverscroll = true;
|
||||
if (mIsRtl) {
|
||||
overScroll(x - mMinScrollX);
|
||||
} else {
|
||||
overScroll(x - mMaxScrollX);
|
||||
}
|
||||
overScroll(primaryScroll - (mIsRtl ? mMinScroll : mMaxScroll));
|
||||
}
|
||||
} else {
|
||||
if (mWasInOverscroll) {
|
||||
@@ -425,7 +473,13 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
super.scrollTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for {@link PagedOrientationHandler} to be able to call parent's scrollTo method
|
||||
*/
|
||||
public void superScrollTo(int x, int y) {
|
||||
super.scrollTo(x, y);
|
||||
}
|
||||
|
||||
private void sendScrollAccessibilityEvent() {
|
||||
@@ -436,9 +490,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
ev.setScrollable(true);
|
||||
ev.setScrollX(getScrollX());
|
||||
ev.setScrollY(getScrollY());
|
||||
ev.setMaxScrollX(mMaxScrollX);
|
||||
ev.setMaxScrollY(0);
|
||||
|
||||
mOrientationHandler.setMaxScroll(ev, mMaxScroll);
|
||||
sendAccessibilityEventUnchecked(ev);
|
||||
}
|
||||
}
|
||||
@@ -459,9 +511,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
protected boolean computeScrollHelper(boolean shouldInvalidate) {
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
// Don't bother scrolling if the page does not need to be moved
|
||||
if (getUnboundedScrollX() != mScroller.getCurrPos()
|
||||
|| getScrollX() != mScroller.getCurrPos()) {
|
||||
scrollTo(mScroller.getCurrPos(), 0);
|
||||
int currentScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||
if (mUnboundedScroll != mScroller.getCurrPos()
|
||||
|| currentScroll != mScroller.getCurrPos()) {
|
||||
mOrientationHandler.set(this, VIEW_SCROLL_TO, mScroller.getCurrPos());
|
||||
}
|
||||
if (shouldInvalidate) {
|
||||
invalidate();
|
||||
@@ -580,7 +633,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
|
||||
|
||||
if (getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC)) {
|
||||
boolean isScrollChanged = getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC);
|
||||
if (isScrollChanged) {
|
||||
pageScrollChanged = true;
|
||||
}
|
||||
|
||||
@@ -621,7 +675,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
/**
|
||||
* Initializes {@code outPageScrolls} with scroll positions for view at that index. The length
|
||||
* of {@code outPageScrolls} should be same as the the childCount
|
||||
*
|
||||
*/
|
||||
protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
|
||||
ComputePageScrollsLogic scrollLogic) {
|
||||
@@ -631,36 +684,30 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
final int endIndex = mIsRtl ? -1 : childCount;
|
||||
final int delta = mIsRtl ? -1 : 1;
|
||||
|
||||
final int verticalCenter = (getPaddingTop() + getMeasuredHeight() + mInsets.top
|
||||
- mInsets.bottom - getPaddingBottom()) / 2;
|
||||
final int pageCenter = mOrientationHandler.getCenterForPage(this, mInsets);
|
||||
|
||||
final int scrollOffsetLeft = mInsets.left + getPaddingLeft();
|
||||
final int scrollOffsetRight = getWidth() - getPaddingRight() - mInsets.right;
|
||||
final int scrollOffsetStart = mOrientationHandler.getScrollOffsetStart(this, mInsets);
|
||||
final int scrollOffsetEnd = mOrientationHandler.getScrollOffsetEnd(this, mInsets);
|
||||
boolean pageScrollChanged = false;
|
||||
|
||||
for (int i = startIndex, childLeft = scrollOffsetLeft; i != endIndex; i += delta) {
|
||||
for (int i = startIndex, childStart = scrollOffsetStart; i != endIndex; i += delta) {
|
||||
final View child = getPageAt(i);
|
||||
if (scrollLogic.shouldIncludeView(child)) {
|
||||
final int childWidth = child.getMeasuredWidth();
|
||||
final int childRight = childLeft + childWidth;
|
||||
|
||||
if (layoutChildren) {
|
||||
final int childHeight = child.getMeasuredHeight();
|
||||
final int childTop = verticalCenter - childHeight / 2;
|
||||
child.layout(childLeft, childTop, childRight, childTop + childHeight);
|
||||
}
|
||||
ChildBounds bounds = mOrientationHandler.getChildBounds(child, childStart,
|
||||
pageCenter, layoutChildren);
|
||||
final int primaryDimension = bounds.primaryDimension;
|
||||
final int childPrimaryEnd = bounds.childPrimaryEnd;
|
||||
|
||||
// In case the pages are of different width, align the page to left or right edge
|
||||
// based on the orientation.
|
||||
final int pageScroll = mIsRtl
|
||||
? (childLeft - scrollOffsetLeft)
|
||||
: Math.max(0, childRight - scrollOffsetRight);
|
||||
? (childStart - scrollOffsetStart)
|
||||
: Math.max(0, childPrimaryEnd - scrollOffsetEnd);
|
||||
if (outPageScrolls[i] != pageScroll) {
|
||||
pageScrollChanged = true;
|
||||
outPageScrolls[i] = pageScroll;
|
||||
}
|
||||
|
||||
childLeft += childWidth + mPageSpacing + getChildGap();
|
||||
childStart += primaryDimension + mPageSpacing + getChildGap();
|
||||
}
|
||||
}
|
||||
return pageScrollChanged;
|
||||
@@ -671,15 +718,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
protected void updateMinAndMaxScrollX() {
|
||||
mMinScrollX = computeMinScrollX();
|
||||
mMaxScrollX = computeMaxScrollX();
|
||||
mMinScroll = computeMinScroll();
|
||||
mMaxScroll = computeMaxScroll();
|
||||
}
|
||||
|
||||
protected int computeMinScrollX() {
|
||||
protected int computeMinScroll() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int computeMaxScrollX() {
|
||||
protected int computeMaxScroll() {
|
||||
int childCount = getChildCount();
|
||||
if (childCount > 0) {
|
||||
final int index = mIsRtl ? 0 : childCount - 1;
|
||||
@@ -722,7 +769,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
protected int getChildOffset(int index) {
|
||||
if (index < 0 || index > getChildCount() - 1) return 0;
|
||||
return getPageAt(index).getLeft();
|
||||
View pageAtIndex = getPageAt(index);
|
||||
return mOrientationHandler.getChildStart(pageAtIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -873,13 +921,13 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
/*
|
||||
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
|
||||
* whether the user has moved far enough from his original down touch.
|
||||
* whether the user has moved far enough from their original down touch.
|
||||
*/
|
||||
if (mActivePointerId != INVALID_POINTER) {
|
||||
determineScrollingStart(ev);
|
||||
}
|
||||
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
|
||||
// event. in that case, treat the first occurence of a move event as a ACTION_DOWN
|
||||
// event. in that case, treat the first occurrence of a move event as a ACTION_DOWN
|
||||
// i.e. fall through to the next case (don't break)
|
||||
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
|
||||
// while it's small- this was causing a crash before we checked for INVALID_POINTER)
|
||||
@@ -892,9 +940,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
// Remember location of down touch
|
||||
mDownMotionX = x;
|
||||
mDownMotionY = y;
|
||||
mLastMotionX = x;
|
||||
mLastMotionXRemainder = 0;
|
||||
mTotalMotionX = 0;
|
||||
mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
|
||||
mLastMotionRemainder = 0;
|
||||
mTotalMotion = 0;
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
|
||||
updateIsBeingDraggedOnTouchDown();
|
||||
@@ -956,17 +1004,17 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) return;
|
||||
|
||||
final float x = ev.getX(pointerIndex);
|
||||
final int xDiff = (int) Math.abs(x - mLastMotionX);
|
||||
final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
|
||||
final int diff = (int) Math.abs(primaryDirection - mLastMotion);
|
||||
final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
|
||||
boolean xMoved = xDiff > touchSlop;
|
||||
boolean moved = diff > touchSlop;
|
||||
|
||||
if (xMoved) {
|
||||
if (moved) {
|
||||
// Scroll if the user moved far enough along the X axis
|
||||
mIsBeingDragged = true;
|
||||
mTotalMotionX += Math.abs(mLastMotionX - x);
|
||||
mLastMotionX = x;
|
||||
mLastMotionXRemainder = 0;
|
||||
mTotalMotion += Math.abs(mLastMotion - primaryDirection);
|
||||
mLastMotion = primaryDirection;
|
||||
mLastMotionRemainder = 0;
|
||||
onScrollInteractionBegin();
|
||||
pageBeginTransition();
|
||||
// Stop listening for things like pinches.
|
||||
@@ -1033,10 +1081,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (mScroller.isSpringing() && mSpringOverScrollX != 0) {
|
||||
if (mScroller.isSpringing() && mSpringOverScroll != 0) {
|
||||
int saveCount = canvas.save();
|
||||
|
||||
canvas.translate(-mSpringOverScrollX, 0);
|
||||
mOrientationHandler.set(canvas, CANVAS_TRANSLATE, -mSpringOverScroll);
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
canvas.restoreToCount(saveCount);
|
||||
@@ -1046,25 +1093,27 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
protected void dampedOverScroll(int amount) {
|
||||
mSpringOverScrollX = amount;
|
||||
mSpringOverScroll = amount;
|
||||
if (amount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
|
||||
mSpringOverScrollX = overScrollAmount;
|
||||
int size = mOrientationHandler.getMeasuredSize(this);
|
||||
int overScrollAmount = OverScroll.dampedScroll(amount, size);
|
||||
mSpringOverScroll = overScrollAmount;
|
||||
if (mScroller.isSpringing()) {
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
int x = Utilities.boundToRange(getScrollX(), mMinScrollX, mMaxScrollX);
|
||||
super.scrollTo(x + overScrollAmount, getScrollY());
|
||||
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||
int boundedScroll = Utilities.boundToRange(primaryScroll, mMinScroll, mMaxScroll);
|
||||
mOrientationHandler.delegateScrollTo(this, boundedScroll + overScrollAmount);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected void overScroll(int amount) {
|
||||
mSpringOverScrollX = amount;
|
||||
mSpringOverScroll = amount;
|
||||
if (mScroller.isSpringing()) {
|
||||
invalidate();
|
||||
return;
|
||||
@@ -1073,11 +1122,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
if (amount == 0) return;
|
||||
|
||||
if (mFreeScroll && !mScroller.isFinished()) {
|
||||
if (amount < 0) {
|
||||
super.scrollTo(mMinScrollX + amount, getScrollY());
|
||||
} else {
|
||||
super.scrollTo(mMaxScrollX + amount, getScrollY());
|
||||
}
|
||||
int scrollAmount = amount < 0 ? mMinScroll + amount : mMaxScroll + amount;
|
||||
mOrientationHandler.delegateScrollTo(this, scrollAmount);
|
||||
} else {
|
||||
dampedOverScroll(amount);
|
||||
}
|
||||
@@ -1127,37 +1173,37 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
// Remember where the motion event started
|
||||
mDownMotionX = mLastMotionX = ev.getX();
|
||||
mDownMotionX = ev.getX();
|
||||
mDownMotionY = ev.getY();
|
||||
mLastMotionXRemainder = 0;
|
||||
mTotalMotionX = 0;
|
||||
mDownMotionPrimary = mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
|
||||
mLastMotionRemainder = 0;
|
||||
mTotalMotion = 0;
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
|
||||
if (mIsBeingDragged) {
|
||||
onScrollInteractionBegin();
|
||||
pageBeginTransition();
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mIsBeingDragged) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mIsBeingDragged) {
|
||||
// Scroll to follow the motion event
|
||||
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
|
||||
if (pointerIndex == -1) return true;
|
||||
|
||||
final float x = ev.getX(pointerIndex);
|
||||
final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
|
||||
|
||||
mTotalMotionX += Math.abs(deltaX);
|
||||
float direction = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
|
||||
float delta = mLastMotion + mLastMotionRemainder - direction;
|
||||
mTotalMotion += Math.abs(delta);
|
||||
|
||||
// Only scroll and update mLastMotionX if we have moved some discrete amount. We
|
||||
// keep the remainder because we are actually testing if we've moved from the last
|
||||
// scrolled position (which is discrete).
|
||||
if (Math.abs(deltaX) >= 1.0f) {
|
||||
scrollBy((int) deltaX, 0);
|
||||
mLastMotionX = x;
|
||||
mLastMotionXRemainder = deltaX - (int) deltaX;
|
||||
if (Math.abs(delta) >= 1.0f) {
|
||||
mLastMotion = direction;
|
||||
mLastMotionRemainder = delta - (int) delta;
|
||||
|
||||
mOrientationHandler.set(this, VIEW_SCROLL_BY, (int) delta);
|
||||
} else {
|
||||
awakenScrollBars();
|
||||
}
|
||||
@@ -1170,27 +1216,31 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
if (mIsBeingDragged) {
|
||||
final int activePointerId = mActivePointerId;
|
||||
final int pointerIndex = ev.findPointerIndex(activePointerId);
|
||||
final float x = ev.getX(pointerIndex);
|
||||
final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev,
|
||||
pointerIndex);
|
||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||
int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
|
||||
final int deltaX = (int) (x - mDownMotionX);
|
||||
final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
|
||||
boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
|
||||
SIGNIFICANT_MOVE_THRESHOLD;
|
||||
|
||||
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
|
||||
boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
|
||||
boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
|
||||
boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
|
||||
int velocity = (int) mOrientationHandler.getPrimaryVelocity(velocityTracker,
|
||||
mActivePointerId);
|
||||
int delta = (int) (primaryDirection - mDownMotionPrimary);
|
||||
int pageOrientedSize = mOrientationHandler.getMeasuredSize(getPageAt(mCurrentPage));
|
||||
|
||||
boolean isSignificantMove = Math.abs(delta) > pageOrientedSize *
|
||||
SIGNIFICANT_MOVE_THRESHOLD;
|
||||
|
||||
mTotalMotion += Math.abs(mLastMotion + mLastMotionRemainder - primaryDirection);
|
||||
boolean isFling = mTotalMotion > mTouchSlop && shouldFlingForVelocity(velocity);
|
||||
boolean isDeltaLeft = mIsRtl ? delta > 0 : delta < 0;
|
||||
boolean isVelocityLeft = mIsRtl ? velocity > 0 : velocity < 0;
|
||||
|
||||
if (!mFreeScroll) {
|
||||
// In the case that the page is moved far to one direction and then is flung
|
||||
// in the opposite direction, we use a threshold to determine whether we should
|
||||
// just return to the starting page, or if we should skip one further.
|
||||
boolean returnToOriginalPage = false;
|
||||
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
|
||||
Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
|
||||
if (Math.abs(delta) > pageOrientedSize * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
|
||||
Math.signum(velocity) != Math.signum(delta) && isFling) {
|
||||
returnToOriginalPage = true;
|
||||
}
|
||||
|
||||
@@ -1199,15 +1249,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
// test for a large move if a fling has been registered. That is, a large
|
||||
// move to the left and fling to the right will register as a fling to the right.
|
||||
|
||||
if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
|
||||
(isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
|
||||
if (((isSignificantMove && !isDeltaLeft && !isFling) ||
|
||||
(isFling && !isVelocityLeft)) && mCurrentPage > 0) {
|
||||
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
|
||||
snapToPageWithVelocity(finalPage, velocityX);
|
||||
} else if (((isSignificantMove && isDeltaXLeft && !isFling) ||
|
||||
(isFling && isVelocityXLeft)) &&
|
||||
snapToPageWithVelocity(finalPage, velocity);
|
||||
} else if (((isSignificantMove && isDeltaLeft && !isFling) ||
|
||||
(isFling && isVelocityLeft)) &&
|
||||
mCurrentPage < getChildCount() - 1) {
|
||||
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
|
||||
snapToPageWithVelocity(finalPage, velocityX);
|
||||
snapToPageWithVelocity(finalPage, velocity);
|
||||
} else {
|
||||
snapToDestination();
|
||||
}
|
||||
@@ -1216,38 +1266,40 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
abortScrollerAnimation(true);
|
||||
}
|
||||
|
||||
int initialScrollX = getScrollX();
|
||||
int initialScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||
int maxScroll = mMaxScroll;
|
||||
int minScroll = mMinScroll;
|
||||
|
||||
if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
|
||||
((initialScrollX <= mMinScrollX) && (!isVelocityXLeft || !isFling))) {
|
||||
mScroller.springBack(getScrollX(), mMinScrollX, mMaxScrollX);
|
||||
if (((initialScroll >= maxScroll) && (isVelocityLeft || !isFling)) ||
|
||||
((initialScroll <= minScroll) && (!isVelocityLeft || !isFling))) {
|
||||
mScroller.springBack(initialScroll, minScroll, maxScroll);
|
||||
mNextPage = getPageNearestToCenterOfScreen();
|
||||
} else {
|
||||
mScroller.setInterpolator(mDefaultInterpolator);
|
||||
mScroller.fling(initialScrollX, -velocityX,
|
||||
mMinScrollX, mMaxScrollX,
|
||||
Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
|
||||
mScroller.fling(initialScroll, -velocity,
|
||||
minScroll, maxScroll,
|
||||
Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
|
||||
|
||||
int finalX = mScroller.getFinalPos();
|
||||
mNextPage = getPageNearestToCenterOfScreen(finalX);
|
||||
int finalPos = mScroller.getFinalPos();
|
||||
mNextPage = getPageNearestToCenterOfScreen(finalPos);
|
||||
|
||||
int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
|
||||
int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
|
||||
if (finalX > mMinScrollX && finalX < mMaxScrollX) {
|
||||
if (finalPos > minScroll && finalPos < maxScroll) {
|
||||
// If scrolling ends in the half of the added space that is closer to
|
||||
// the end, settle to the end. Otherwise snap to the nearest page.
|
||||
// If flinging past one of the ends, don't change the velocity as it
|
||||
// will get stopped at the end anyway.
|
||||
int pageSnappedX = finalX < (firstPageScroll + mMinScrollX) / 2
|
||||
? mMinScrollX
|
||||
: finalX > (lastPageScroll + mMaxScrollX) / 2
|
||||
? mMaxScrollX
|
||||
: getScrollForPage(mNextPage);
|
||||
int pageSnapped = finalPos < (firstPageScroll + minScroll) / 2
|
||||
? minScroll
|
||||
: finalPos > (lastPageScroll + maxScroll) / 2
|
||||
? maxScroll
|
||||
: getScrollForPage(mNextPage);
|
||||
|
||||
mScroller.setFinalPos(pageSnappedX);
|
||||
mScroller.setFinalPos(pageSnapped);
|
||||
// Ensure the scroll/snap doesn't happen too fast;
|
||||
int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
|
||||
- mScroller.getDuration();
|
||||
- mScroller.getDuration();
|
||||
if (extraScrollDuration > 0) {
|
||||
mScroller.extendDuration(extraScrollDuration);
|
||||
}
|
||||
@@ -1279,8 +1331,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean shouldFlingForVelocity(int velocityX) {
|
||||
return Math.abs(velocityX) > mFlingThresholdVelocity;
|
||||
protected boolean shouldFlingForVelocity(int velocity) {
|
||||
return Math.abs(velocity) > mFlingThresholdVelocity;
|
||||
}
|
||||
|
||||
private void resetTouchState() {
|
||||
@@ -1364,8 +1416,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
// active pointer and adjust accordingly.
|
||||
// TODO: Make this decision more intelligent.
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||
mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
|
||||
mLastMotionXRemainder = 0;
|
||||
mLastMotion = mDownMotionPrimary = mOrientationHandler.getPrimaryDirection(ev,
|
||||
newPointerIndex);
|
||||
mLastMotionRemainder = 0;
|
||||
mActivePointerId = ev.getPointerId(newPointerIndex);
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.clear();
|
||||
@@ -1383,19 +1436,20 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
public int getPageNearestToCenterOfScreen() {
|
||||
return getPageNearestToCenterOfScreen(getScrollX());
|
||||
return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this));
|
||||
}
|
||||
|
||||
private int getPageNearestToCenterOfScreen(int scaledScrollX) {
|
||||
int screenCenter = scaledScrollX + (getMeasuredWidth() / 2);
|
||||
private int getPageNearestToCenterOfScreen(int scaledScroll) {
|
||||
int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
|
||||
int screenCenter = scaledScroll + (pageOrientationSize / 2);
|
||||
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
|
||||
int minDistanceFromScreenCenterIndex = -1;
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
View layout = getPageAt(i);
|
||||
int childWidth = layout.getMeasuredWidth();
|
||||
int halfChildWidth = (childWidth / 2);
|
||||
int childCenter = getChildOffset(i) + halfChildWidth;
|
||||
int childSize = mOrientationHandler.getMeasuredSize(layout);
|
||||
int halfChildSize = (childSize / 2);
|
||||
int childCenter = getChildOffset(i) + halfChildSize;
|
||||
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
|
||||
if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
|
||||
minDistanceFromScreenCenter = distanceFromScreenCenter;
|
||||
@@ -1410,7 +1464,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
protected boolean isInOverScroll() {
|
||||
return (getScrollX() > mMaxScrollX || getScrollX() < mMinScrollX);
|
||||
int scroll = mOrientationHandler.getPrimaryScroll(this);
|
||||
return scroll > mMaxScroll || scroll < mMinScroll;
|
||||
}
|
||||
|
||||
protected int getPageSnapDuration() {
|
||||
@@ -1432,10 +1487,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
protected boolean snapToPageWithVelocity(int whichPage, int velocity) {
|
||||
whichPage = validateNewPage(whichPage);
|
||||
int halfScreenSize = getMeasuredWidth() / 2;
|
||||
int halfScreenSize = mOrientationHandler.getMeasuredSize(this) / 2;
|
||||
|
||||
final int newX = getScrollForPage(whichPage);
|
||||
int delta = newX - getUnboundedScrollX();
|
||||
final int newLoc = getScrollForPage(whichPage);
|
||||
int delta = newLoc - getUnboundedScroll();
|
||||
int duration = 0;
|
||||
|
||||
if (Math.abs(velocity) < mMinFlingVelocity) {
|
||||
@@ -1462,7 +1517,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
if (QUICKSTEP_SPRINGS.get()) {
|
||||
return snapToPage(whichPage, delta, duration, false, null,
|
||||
velocity * Math.signum(newX - getUnboundedScrollX()), true);
|
||||
velocity * Math.signum(delta), true);
|
||||
} else {
|
||||
return snapToPage(whichPage, delta, duration);
|
||||
}
|
||||
@@ -1488,8 +1543,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
TimeInterpolator interpolator) {
|
||||
whichPage = validateNewPage(whichPage);
|
||||
|
||||
int newX = getScrollForPage(whichPage);
|
||||
final int delta = newX - getUnboundedScrollX();
|
||||
int newLoc = getScrollForPage(whichPage);
|
||||
final int delta = newLoc - getUnboundedScroll();
|
||||
return snapToPage(whichPage, delta, duration, immediate, interpolator, 0, false);
|
||||
}
|
||||
|
||||
@@ -1535,9 +1590,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
if (spring && QUICKSTEP_SPRINGS.get()) {
|
||||
mScroller.startScrollSpring(getUnboundedScrollX(), delta, duration, velocity);
|
||||
mScroller.startScrollSpring(getUnboundedScroll(), delta, duration, velocity);
|
||||
} else {
|
||||
mScroller.startScroll(getUnboundedScrollX(), delta, duration);
|
||||
mScroller.startScroll(getUnboundedScroll(), delta, duration);
|
||||
}
|
||||
|
||||
updatePageIndicator();
|
||||
|
||||
@@ -21,12 +21,12 @@ import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
|
||||
public class ResourceUtils {
|
||||
public static final int DEFAULT_NAVBAR_VALUE = 48;
|
||||
public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
|
||||
public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
|
||||
|
||||
|
||||
public static int getNavbarSize(String resName, Resources res) {
|
||||
return getDimenByName(resName, res, 48);
|
||||
return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
|
||||
}
|
||||
|
||||
public static int getDimenByName(String resName, Resources res, int defaultValue) {
|
||||
|
||||
@@ -67,7 +67,6 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
mCacheExpireAlarm = new Alarm();
|
||||
mCacheExpireAlarm.setOnAlarmListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,6 +74,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
super.onAttachedToWindow();
|
||||
if (mHadPendingAlarm) {
|
||||
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
||||
mCacheExpireAlarm.setOnAlarmListener(this);
|
||||
mHadPendingAlarm = false;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
super.onDetachedFromWindow();
|
||||
if (mCacheExpireAlarm.alarmPending()) {
|
||||
mCacheExpireAlarm.cancelAlarm();
|
||||
mCacheExpireAlarm.setOnAlarmListener(null);
|
||||
mHadPendingAlarm = true;
|
||||
}
|
||||
}
|
||||
@@ -168,6 +169,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
}
|
||||
// Cancel any pending alarm and set cache expiry after some time
|
||||
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
||||
mCacheExpireAlarm.setOnAlarmListener(this);
|
||||
if (uninstallDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
|
||||
import static com.android.launcher3.states.RotationHelper.FIXED_ROTATION_TRANSFORM_SETTING_NAME;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
@@ -127,6 +128,11 @@ public final class Utilities {
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
|
||||
}
|
||||
|
||||
public static boolean isForcedRotation(Context context) {
|
||||
return Settings.Global.getInt(context.getContentResolver(),
|
||||
FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
|
||||
}
|
||||
|
||||
// An intent extra to indicate the horizontal scroll of the wallpaper.
|
||||
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
|
||||
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
|
||||
|
||||
@@ -966,8 +966,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
private boolean isScrollingOverlay() {
|
||||
return mLauncherOverlay != null &&
|
||||
((mIsRtl && getUnboundedScrollX() > mMaxScrollX)
|
||||
|| (!mIsRtl && getUnboundedScrollX() < mMinScrollX));
|
||||
((mIsRtl && getUnboundedScroll() > mMaxScroll)
|
||||
|| (!mIsRtl && getUnboundedScroll() < mMinScroll));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1003,7 +1003,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
public void showPageIndicatorAtCurrentScroll() {
|
||||
if (mPageIndicator != null) {
|
||||
mPageIndicator.setScroll(getScrollX(), computeMaxScrollX());
|
||||
mPageIndicator.setScroll(getScrollX(), computeMaxScroll());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
protected boolean mUsingTabs;
|
||||
private boolean mSearchModeWhileUsingTabs = false;
|
||||
|
||||
private RecyclerViewFastScroller mTouchHandler;
|
||||
private final Point mFastScrollerOffset = new Point();
|
||||
protected RecyclerViewFastScroller mTouchHandler;
|
||||
protected final Point mFastScrollerOffset = new Point();
|
||||
|
||||
private final MultiValueAlpha mMultiValueAlpha;
|
||||
|
||||
@@ -238,6 +238,16 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
|
||||
mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
} else {
|
||||
mTouchHandler = null;
|
||||
|
||||
}
|
||||
}
|
||||
if (mTouchHandler != null) {
|
||||
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
||||
return true;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
mPageIndicator.setScroll(l, mMaxScrollX);
|
||||
mPageIndicator.setScroll(l, mMaxScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,8 +32,10 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
/**
|
||||
* Handles AllApps view transition.
|
||||
@@ -47,9 +49,6 @@ import com.android.launcher3.views.ScrimView;
|
||||
*/
|
||||
public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
|
||||
|
||||
private static final float SPRING_DAMPING_RATIO = 0.75f;
|
||||
private static final float SPRING_STIFFNESS = 600f;
|
||||
|
||||
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
|
||||
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
|
||||
|
||||
@@ -187,8 +186,12 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
|
||||
|
||||
public Animator createSpringAnimation(float... progressValues) {
|
||||
if (UNSTABLE_SPRINGS.get()) {
|
||||
ResourceProvider rp = DynamicResource.provider(mLauncher);
|
||||
float damping = rp.getFloat(R.dimen.all_apps_spring_damping_ratio);
|
||||
float stiffness = rp.getFloat(R.dimen.all_apps_spring_stiffness);
|
||||
|
||||
return new SpringObjectAnimator<>(this, ALL_APPS_PROGRESS, 1f / mShiftRange,
|
||||
SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
|
||||
damping, stiffness, progressValues);
|
||||
}
|
||||
return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,10 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
// The AllAppsContainerView houses the QSB and is hence visible from the Workspace
|
||||
// Overview states. We shouldn't intercept for the scrubber in these cases.
|
||||
if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
|
||||
if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
|
||||
mTouchHandler = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@@ -15,32 +15,40 @@
|
||||
*/
|
||||
package com.android.launcher3.anim;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
||||
import androidx.dynamicanimation.animation.FlingAnimation;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
/**
|
||||
* Given a property to animate and a target value and starting velocity, first apply friction to
|
||||
* the fling until we pass the target, then apply a spring force to pull towards the target.
|
||||
*/
|
||||
public class FlingSpringAnim {
|
||||
|
||||
private static final float FLING_FRICTION = 1.5f;
|
||||
private static final float SPRING_STIFFNESS = 200;
|
||||
private static final float SPRING_DAMPING = 0.8f;
|
||||
|
||||
private final FlingAnimation mFlingAnim;
|
||||
private SpringAnimation mSpringAnim;
|
||||
|
||||
private float mTargetPosition;
|
||||
|
||||
public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
|
||||
float targetPosition, float startVelocity, float minVisChange, float minValue,
|
||||
float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
|
||||
public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
|
||||
float startPosition, float targetPosition, float startVelocity, float minVisChange,
|
||||
float minValue, float maxValue, float springVelocityFactor,
|
||||
OnAnimationEndListener onEndListener) {
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
|
||||
float stiffness = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness);
|
||||
float friction = rp.getFloat(R.dimen.swipe_up_rect_xy_fling_friction);
|
||||
|
||||
mFlingAnim = new FlingAnimation(object, property)
|
||||
.setFriction(FLING_FRICTION)
|
||||
.setFriction(friction)
|
||||
// Have the spring pull towards the target if we've slowed down too much before
|
||||
// reaching it.
|
||||
.setMinimumVisibleChange(minVisChange)
|
||||
@@ -54,8 +62,8 @@ public class FlingSpringAnim {
|
||||
.setStartValue(value)
|
||||
.setStartVelocity(velocity * springVelocityFactor)
|
||||
.setSpring(new SpringForce(mTargetPosition)
|
||||
.setStiffness(SPRING_STIFFNESS)
|
||||
.setDampingRatio(SPRING_DAMPING));
|
||||
.setStiffness(stiffness)
|
||||
.setDampingRatio(damping));
|
||||
mSpringAnim.addEndListener(onEndListener);
|
||||
mSpringAnim.animateToFinalPosition(mTargetPosition);
|
||||
}));
|
||||
|
||||
@@ -101,11 +101,15 @@ public final class FeatureFlags {
|
||||
"Adds localized title and keyword search and ranking");
|
||||
|
||||
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
|
||||
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
|
||||
"ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
|
||||
|
||||
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
|
||||
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
|
||||
|
||||
public static final BooleanFlag FORCE_LOCAL_OVERSCROLL_PLUGIN = getDebugFlag(
|
||||
"FORCE_LOCAL_OVERSCROLL_PLUGIN", false,
|
||||
"Use a launcher-provided OverscrollPlugin if available");
|
||||
|
||||
public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(
|
||||
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
|
||||
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
|
||||
@@ -113,6 +117,10 @@ public final class FeatureFlags {
|
||||
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
|
||||
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
|
||||
|
||||
public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = new DeviceFlag(
|
||||
"HOTSEAT_MIGRATE_NEW_PAGE", true,
|
||||
"Migrates hotseat to a new workspace page instead of same page");
|
||||
|
||||
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
|
||||
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
|
||||
|
||||
@@ -120,7 +128,7 @@ public final class FeatureFlags {
|
||||
"MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm");
|
||||
|
||||
public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
|
||||
"ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", false,
|
||||
"ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true,
|
||||
"Show launcher preview in grid picker");
|
||||
|
||||
public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
|
||||
@@ -139,6 +147,11 @@ public final class FeatureFlags {
|
||||
"ENABLE_LSQ_VELOCITY_PROVIDER", false,
|
||||
"Use Least Square algorithm for motion pause detection.");
|
||||
|
||||
public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
|
||||
getDebugFlag(
|
||||
"ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false,
|
||||
"Always use hardware optimization for folder animations.");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
|
||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
|
||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY;
|
||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED;
|
||||
@@ -546,6 +547,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
|
||||
if (ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS.get()) return true;
|
||||
|
||||
int folderCount = 0;
|
||||
final ShortcutAndWidgetContainer container = currentCellLayout.getShortcutsAndWidgets();
|
||||
for (int i = container.getChildCount() - 1; i >= 0; --i) {
|
||||
|
||||
@@ -258,7 +258,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
mPageIndicator.setScroll(l, mMaxScrollX);
|
||||
mPageIndicator.setScroll(l, mMaxScroll);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,9 +87,11 @@ import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.WidgetsModel;
|
||||
import com.android.launcher3.pm.InstallSessionHelper;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -128,7 +130,8 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
|
||||
private static final Set<MainThreadInitializedObject> WHITELIST = new HashSet<>(
|
||||
Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE));
|
||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
||||
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE));
|
||||
|
||||
private final InvariantDeviceProfile mIdp;
|
||||
private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
|
||||
@@ -145,6 +148,14 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
CustomWidgetManager customWidgetManager = (CustomWidgetManager) mObjectMap.get(
|
||||
CustomWidgetManager.INSTANCE);
|
||||
if (customWidgetManager != null) {
|
||||
customWidgetManager.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a cached object from mObjectMap if we have already created one. If not, generate
|
||||
* an object using the provider.
|
||||
@@ -349,6 +360,9 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
|
||||
WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
|
||||
info.providerName);
|
||||
if (widgetItem == null) {
|
||||
return;
|
||||
}
|
||||
AppWidgetHostView view = new AppWidgetHostView(mContext);
|
||||
view.setAppWidget(-1, widgetItem.widgetInfo);
|
||||
view.updateAppWidget(null);
|
||||
@@ -385,9 +399,11 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
}
|
||||
|
||||
WorkspaceFetcher fetcher;
|
||||
PreviewContext previewContext = null;
|
||||
if (needsToMigrate && success) {
|
||||
previewContext = new PreviewContext(mContext, mIdp);
|
||||
LauncherAppState appForPreview = new LauncherAppState(
|
||||
new PreviewContext(mContext, mIdp), null /* iconCacheFileName */);
|
||||
previewContext, null /* iconCacheFileName */);
|
||||
fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
|
||||
MODEL_EXECUTOR.execute(fetcher);
|
||||
} else {
|
||||
@@ -396,6 +412,9 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
(LauncherModel.ModelUpdateTask) fetcher);
|
||||
}
|
||||
WorkspaceResult workspaceResult = fetcher.get();
|
||||
if (previewContext != null) {
|
||||
previewContext.onDestroy();
|
||||
}
|
||||
|
||||
if (workspaceResult == null) {
|
||||
return;
|
||||
@@ -557,6 +576,7 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
public WorkspaceResult call() throws Exception {
|
||||
List<ShortcutInfo> allShortcuts = new ArrayList<>();
|
||||
loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI);
|
||||
mBgDataModel.widgetsModel.update(mApp, null);
|
||||
return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets,
|
||||
mBgDataModel.widgetsModel);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class FileLog {
|
||||
private static final DateFormat DATE_FORMAT =
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
|
||||
private static final long MAX_LOG_FILE_SIZE = 4 << 20; // 4 mb
|
||||
private static final long MAX_LOG_FILE_SIZE = 8 << 20; // 4 mb
|
||||
|
||||
private static Handler sHandler = null;
|
||||
private static File sLogsDirectory = null;
|
||||
|
||||
@@ -104,7 +104,7 @@ import java.util.concurrent.CancellationException;
|
||||
public class LoaderTask implements Runnable {
|
||||
private static final String TAG = "LoaderTask";
|
||||
|
||||
private final LauncherAppState mApp;
|
||||
protected final LauncherAppState mApp;
|
||||
private final AllAppsList mBgAllAppsList;
|
||||
protected final BgDataModel mBgDataModel;
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright (C) 2020 The Android Open Source Project
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.touch.PortraitPagedViewHandler;
|
||||
import com.android.launcher3.touch.LandscapePagedViewHandler;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.SeascapePagedViewHandler;
|
||||
|
||||
/**
|
||||
* Container to hold orientation/rotation related information for Launcher.
|
||||
* This is not meant to be an abstraction layer for applying different functionality between
|
||||
* the different orientation/rotations. For that see {@link PagedOrientationHandler}
|
||||
*
|
||||
* This class has initial default state assuming the device and foreground app have
|
||||
* no ({@link Surface.ROTATION_0} rotation.
|
||||
*
|
||||
* Currently this class resides in {@link com.android.launcher3.PagedView}, but there's a ticket
|
||||
* to disassociate it from Launcher since it's needed before Launcher is instantiated
|
||||
* See TODO(b/150300347)
|
||||
*/
|
||||
public final class PagedViewOrientedState {
|
||||
|
||||
private PagedOrientationHandler mOrientationHandler = new PortraitPagedViewHandler();
|
||||
|
||||
private int mTouchRotation = Surface.ROTATION_0;
|
||||
private int mDisplayRotation = Surface.ROTATION_0;
|
||||
/**
|
||||
* If {@code true} we default to {@link PortraitPagedViewHandler} and don't support any fake
|
||||
* launcher orientations.
|
||||
*/
|
||||
private boolean mDisableMultipleOrientations;
|
||||
|
||||
public void update(int touchRotation, int displayRotation) {
|
||||
mDisplayRotation = displayRotation;
|
||||
mTouchRotation = touchRotation;
|
||||
if (mTouchRotation == Surface.ROTATION_90) {
|
||||
mOrientationHandler = new LandscapePagedViewHandler();
|
||||
} else if (mTouchRotation == Surface.ROTATION_270) {
|
||||
mOrientationHandler = new SeascapePagedViewHandler();
|
||||
} else {
|
||||
mOrientationHandler = new PortraitPagedViewHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the area where the user touched the nav bar is the expected
|
||||
* location for the given display rotation. Ex. bottom of phone in portrait, or left side of
|
||||
* phone in landscape, right side in seascape, etc.
|
||||
* False otherwise
|
||||
*/
|
||||
public boolean isTouchRegionNaturalForDisplay() {
|
||||
return mTouchRotation == mDisplayRotation;
|
||||
}
|
||||
|
||||
public boolean areMultipleLayoutOrientationsDisabled() {
|
||||
return mDisableMultipleOrientations;
|
||||
}
|
||||
|
||||
public void disableMultipleOrientations(boolean disable) {
|
||||
mDisableMultipleOrientations = disable;
|
||||
if (disable) {
|
||||
mOrientationHandler = new PortraitPagedViewHandler();
|
||||
}
|
||||
}
|
||||
|
||||
public int getDisplayRotation() {
|
||||
return mDisplayRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the difference between the rotation of the device/display and which region the
|
||||
* user is currently interacting with in factors of 90 degree clockwise rotations.
|
||||
* Ex. Display is in portrait -> 0, user touches landscape region -> 1, this
|
||||
* method would return 3 because it takes 3 clockwise 90 degree rotations from normal to
|
||||
* landscape (portrait -> seascape -> reverse portrait -> landscape)
|
||||
*/
|
||||
public int getTouchDisplayDelta() {
|
||||
return RotationHelper.deltaRotation(mTouchRotation, mDisplayRotation);
|
||||
}
|
||||
|
||||
public PagedOrientationHandler getOrientationHandler() {
|
||||
return mOrientationHandler;
|
||||
}
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public class NotificationMainView extends FrameLayout implements SingleAxisSwipe
|
||||
|
||||
// SingleAxisSwipeDetector.Listener's
|
||||
@Override
|
||||
public void onDragStart(boolean start) { }
|
||||
public void onDragStart(boolean start, float startDisplacement) { }
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
@@ -96,6 +96,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
initFlags();
|
||||
loadPluginPrefs();
|
||||
maybeAddSandboxCategory();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,6 +204,31 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
|
||||
});
|
||||
}
|
||||
|
||||
private void maybeAddSandboxCategory() {
|
||||
Context context = getContext();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
Intent launchSandboxIntent =
|
||||
new Intent("com.android.quickstep.action.GESTURE_SANDBOX")
|
||||
.setPackage(context.getPackageName())
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (launchSandboxIntent.resolveActivity(context.getPackageManager()) == null) {
|
||||
return;
|
||||
}
|
||||
PreferenceCategory sandboxCategory = newCategory("Sandbox");
|
||||
Preference launchSandboxPreference = new Preference(context);
|
||||
launchSandboxPreference.setKey("launchSandbox");
|
||||
launchSandboxPreference.setTitle("Launch Gesture Navigation Sandbox");
|
||||
launchSandboxPreference.setSummary(
|
||||
"This provides tutorials and a place to practice navigation gestures.");
|
||||
launchSandboxPreference.setOnPreferenceClickListener(preference -> {
|
||||
startActivity(launchSandboxIntent);
|
||||
return true;
|
||||
});
|
||||
sandboxCategory.addPreference(launchSandboxPreference);
|
||||
}
|
||||
|
||||
private String toName(String action) {
|
||||
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
|
||||
.replace("com.android.launcher3.action.PLUGIN_", "");
|
||||
|
||||
@@ -17,20 +17,35 @@ package com.android.launcher3.states;
|
||||
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.provider.Settings;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class to manage launcher rotation
|
||||
*/
|
||||
@@ -38,15 +53,39 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
|
||||
public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
|
||||
|
||||
public static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
|
||||
private final ContentResolver mContentResolver;
|
||||
|
||||
/**
|
||||
* Listener to receive changes when {@link #FIXED_ROTATION_TRANSFORM_SETTING_NAME} flag changes.
|
||||
*/
|
||||
public interface ForcedRotationChangedListener {
|
||||
void onForcedRotationChanged(boolean isForcedRotation);
|
||||
}
|
||||
|
||||
public static boolean getAllowRotationDefaultValue() {
|
||||
// If the device was scaled, used the original dimensions to determine if rotation
|
||||
// is allowed of not.
|
||||
// If the device's pixel density was scaled (usually via settings for A11y), use the
|
||||
// original dimensions to determine if rotation is allowed of not.
|
||||
Resources res = Resources.getSystem();
|
||||
int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
|
||||
* res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
|
||||
return originalSmallestWidth >= 600;
|
||||
}
|
||||
|
||||
|
||||
private final ContentObserver mContentObserver =
|
||||
new ContentObserver(MAIN_EXECUTOR.getHandler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
boolean forcedRotation = Utilities.isForcedRotation(mLauncher);
|
||||
PagedView.sFlagForcedRotation = forcedRotation;
|
||||
updateForcedRotation();
|
||||
for (ForcedRotationChangedListener listener : mForcedRotationChangedListeners) {
|
||||
listener.onForcedRotationChanged(forcedRotation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static final int REQUEST_NONE = 0;
|
||||
public static final int REQUEST_ROTATE = 1;
|
||||
public static final int REQUEST_LOCK = 2;
|
||||
@@ -56,6 +95,8 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private boolean mIgnoreAutoRotateSettings;
|
||||
private boolean mAutoRotateEnabled;
|
||||
private boolean mForcedRotation;
|
||||
private List<ForcedRotationChangedListener> mForcedRotationChangedListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Rotation request made by
|
||||
@@ -84,6 +125,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
|
||||
// On large devices we do not handle auto-rotate differently.
|
||||
mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
|
||||
updateForcedRotation();
|
||||
if (!mIgnoreAutoRotateSettings) {
|
||||
mPrefs = Utilities.getPrefs(mLauncher);
|
||||
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||
@@ -92,6 +134,26 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
} else {
|
||||
mPrefs = null;
|
||||
}
|
||||
|
||||
// TODO(b/150260456) Add this in home settings as well
|
||||
mContentResolver = launcher.getContentResolver();
|
||||
mContentResolver.registerContentObserver(Settings.Global.getUriFor(
|
||||
FIXED_ROTATION_TRANSFORM_SETTING_NAME), false, mContentObserver);
|
||||
}
|
||||
|
||||
private void updateForcedRotation() {
|
||||
mForcedRotation = !getAllowRotationDefaultValue() && Utilities.isForcedRotation(mLauncher);
|
||||
}
|
||||
|
||||
/**
|
||||
* will not be called when first registering the listener.
|
||||
*/
|
||||
public void addForcedRotationCallback(ForcedRotationChangedListener listener) {
|
||||
mForcedRotationChangedListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeForcedRotationCallback(ForcedRotationChangedListener listener) {
|
||||
mForcedRotationChangedListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
|
||||
@@ -173,6 +235,10 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
if (mPrefs != null) {
|
||||
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
if (mContentResolver != null) {
|
||||
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
mForcedRotationChangedListeners.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +248,10 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
}
|
||||
|
||||
final int activityFlags;
|
||||
if (mStateHandlerRequest != REQUEST_NONE) {
|
||||
if (mForcedRotation) {
|
||||
// TODO(b/150214193) Properly address this
|
||||
activityFlags = SCREEN_ORIENTATION_PORTRAIT;
|
||||
} else if (mStateHandlerRequest != REQUEST_NONE) {
|
||||
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
|
||||
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
|
||||
@@ -204,6 +273,118 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDegreesFromRotation(int rotation) {
|
||||
int degrees;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
case Surface.ROTATION_0:
|
||||
default:
|
||||
degrees = 0;
|
||||
break;
|
||||
}
|
||||
return degrees;
|
||||
}
|
||||
|
||||
public static int getRotationFromDegrees(int degrees) {
|
||||
int threshold = 70;
|
||||
if (degrees >= (360 - threshold) || degrees < (threshold)) {
|
||||
return Surface.ROTATION_0;
|
||||
} else if (degrees < (90 + threshold)) {
|
||||
return Surface.ROTATION_270;
|
||||
} else if (degrees < 180 + threshold) {
|
||||
return Surface.ROTATION_180;
|
||||
} else {
|
||||
return Surface.ROTATION_90;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return how many factors {@param newRotation} is rotated 90 degrees clockwise.
|
||||
* E.g. 1->Rotated by 90 degrees clockwise, 2->Rotated 180 clockwise...
|
||||
* A value of 0 means no rotation has been applied
|
||||
*/
|
||||
public static int deltaRotation(int oldRotation, int newRotation) {
|
||||
int delta = newRotation - oldRotation;
|
||||
if (delta < 0) delta += 4;
|
||||
return delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a matrix to transform the given motion event specified by degrees.
|
||||
* If {@param inverse} is {@code true}, the inverse of that matrix will be applied
|
||||
*/
|
||||
public static void transformEvent(float degrees, MotionEvent ev, boolean inverse) {
|
||||
Matrix transform = new Matrix();
|
||||
transform.setRotate(degrees);
|
||||
if (inverse) {
|
||||
Matrix inv = new Matrix();
|
||||
transform.invert(inv);
|
||||
ev.transform(inv);
|
||||
} else {
|
||||
ev.transform(transform);
|
||||
}
|
||||
// TODO: Add scaling back in based on degrees
|
||||
// if (getWidth() > 0 && getHeight() > 0) {
|
||||
// float scale = ((float) getWidth()) / getHeight();
|
||||
// transform.postScale(scale, 1 / scale);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/149658423): Have {@link com.android.quickstep.OrientationTouchTransformer
|
||||
* also use this}
|
||||
*/
|
||||
public static Matrix getRotationMatrix(int screenWidth, int screenHeight, int displayRotation) {
|
||||
Matrix m = new Matrix();
|
||||
switch (displayRotation) {
|
||||
case Surface.ROTATION_0:
|
||||
return m;
|
||||
case Surface.ROTATION_90:
|
||||
m.setRotate(360 - RotationHelper.getDegreesFromRotation(displayRotation));
|
||||
m.postTranslate(0, screenWidth);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
m.setRotate(360 - RotationHelper.getDegreesFromRotation(displayRotation));
|
||||
m.postTranslate(screenHeight, 0);
|
||||
break;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public static void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight,
|
||||
int displayRotation) {
|
||||
Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
|
||||
m.mapRect(src);
|
||||
}
|
||||
|
||||
public static void mapInverseRectFromNormalOrientation(RectF src, int screenWidth,
|
||||
int screenHeight, int displayRotation) {
|
||||
Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
|
||||
Matrix inverse = new Matrix();
|
||||
m.invert(inverse);
|
||||
inverse.mapRect(src);
|
||||
}
|
||||
|
||||
public static void getTargetRectForRotation(Rect srcOut, int screenWidth, int screenHeight,
|
||||
int displayRotation) {
|
||||
RectF wrapped = new RectF(srcOut);
|
||||
Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
|
||||
m.mapRect(wrapped);
|
||||
wrapped.round(srcOut);
|
||||
}
|
||||
|
||||
public static boolean isRotationLandscape(int rotation) {
|
||||
return rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
|
||||
|
||||
@@ -230,7 +230,7 @@ public abstract class AbstractStateChangeTouchController
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
mStartState = mLauncher.getStateManager().getState();
|
||||
mIsLogContainerSet = false;
|
||||
if (mCurrentAnimation == null) {
|
||||
|
||||
@@ -236,7 +236,7 @@ public abstract class BaseSwipeDetector {
|
||||
} else {
|
||||
mSubtractDisplacement.x = mDisplacement.x > 0 ? mTouchSlop : -mTouchSlop;
|
||||
mSubtractDisplacement.y = mDisplacement.y > 0 ? mTouchSlop : -mTouchSlop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean shouldScrollStart(PointF displacement);
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.touch;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
|
||||
|
||||
public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||
|
||||
@Override
|
||||
public int getPrimaryValue(int x, int y) {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondaryValue(int x, int y) {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollTo(PagedView pagedView, int secondaryScroll, int minMaxScroll) {
|
||||
pagedView.superScrollTo(secondaryScroll, minMaxScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y) {
|
||||
pagedView.scrollTo(pagedView.getScrollX() + x, unboundedScroll + y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollerStartScroll(OverScroller scroller, int newPosition) {
|
||||
scroller.startScroll(scroller.getCurrPos(), newPosition - scroller.getCurrPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
|
||||
int scroll = pagedView.getScrollY();
|
||||
final int halfPageSize = pagedView.getNormalChildHeight() / 2;
|
||||
final int screenCenter = mInsets.top + pagedView.getPaddingTop() + scroll + halfPageSize;
|
||||
final int halfScreenSize = pagedView.getMeasuredHeight() / 2;
|
||||
return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGoingUp(float displacement) {
|
||||
return displacement > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustFloatingIconStartVelocity(PointF velocity) {
|
||||
float oldX = velocity.x;
|
||||
float oldY = velocity.y;
|
||||
velocity.set(-oldY, oldX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollTo(PagedView pagedView, int primaryScroll) {
|
||||
pagedView.superScrollTo(pagedView.getScrollX(), primaryScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void set(T target, Int2DAction<T> action, int param) {
|
||||
action.call(target, 0, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void set(T target, Float2DAction<T> action, float param) {
|
||||
action.call(target, 0, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
|
||||
return event.getY(pointerIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
|
||||
return velocityTracker.getYVelocity(pointerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMeasuredSize(View view) {
|
||||
return view.getMeasuredHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimarySize(Rect rect) {
|
||||
return rect.height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimarySize(RectF rect) {
|
||||
return rect.height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondaryDimension(View view) {
|
||||
return view.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
|
||||
float offscreenTranslationY = dp.heightPx - view.getPaddingTop();
|
||||
return new ScaleAndTranslation(1f, 0f, offscreenTranslationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
|
||||
return scaleAndTranslation.translationY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatProperty<View> getPrimaryViewTranslate() {
|
||||
return VIEW_TRANSLATE_Y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatProperty<View> getSecondaryViewTranslate() {
|
||||
return VIEW_TRANSLATE_X;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryAndResetSecondaryTranslate(View view, float translation) {
|
||||
view.setTranslationX(0);
|
||||
view.setTranslationY(translation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getViewCenterPosition(View view) {
|
||||
return view.getTop() + view.getTranslationY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimaryScroll(View view) {
|
||||
return view.getScrollY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryScale(View view) {
|
||||
return view.getScaleY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
|
||||
event.setMaxScrollY(maxScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRecentsRtlSetting(Resources resources) {
|
||||
return !Utilities.isRtl(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDegreesRotated() {
|
||||
return 90;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offsetTaskRect(RectF rect, float value, int displayRotation) {
|
||||
if (displayRotation == Surface.ROTATION_0) {
|
||||
rect.offset(0, value);
|
||||
} else if (displayRotation == Surface.ROTATION_90) {
|
||||
rect.offset(value, 0);
|
||||
} else if (displayRotation == Surface.ROTATION_180) {
|
||||
rect.offset(0, -value);
|
||||
} else {
|
||||
rect.offset(-value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildStart(View view) {
|
||||
return view.getTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCenterForPage(View view, Rect insets) {
|
||||
return (view.getPaddingLeft() + view.getMeasuredWidth() + insets.left
|
||||
- insets.right - view.getPaddingRight()) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollOffsetStart(View view, Rect insets) {
|
||||
return insets.top + view.getPaddingTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollOffsetEnd(View view, Rect insets) {
|
||||
return view.getHeight() - view.getPaddingBottom() - insets.bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleAxisSwipeDetector.Direction getOppositeSwipeDirection() {
|
||||
return HORIZONTAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShortEdgeLength(DeviceProfile dp) {
|
||||
return dp.heightPx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaskDismissDirectionFactor() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
|
||||
boolean layoutChild) {
|
||||
final int childHeight = child.getMeasuredHeight();
|
||||
final int childBottom = childStart + childHeight;
|
||||
final int childWidth = child.getMeasuredWidth();
|
||||
final int childLeft = pageCenter - childWidth/ 2;
|
||||
if (layoutChild) {
|
||||
child.layout(childLeft, childStart, childLeft + childWidth, childBottom);
|
||||
}
|
||||
return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.touch;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
|
||||
/**
|
||||
* Abstraction layer to separate horizontal and vertical specific implementations
|
||||
* for {@link com.android.launcher3.PagedView}. Majority of these implementations are (should be) as
|
||||
* simple as choosing the correct X and Y analogous methods.
|
||||
*/
|
||||
public interface PagedOrientationHandler {
|
||||
|
||||
interface Int2DAction<T> {
|
||||
void call(T target, int x, int y);
|
||||
}
|
||||
interface Float2DAction<T> {
|
||||
void call(T target, float x, float y);
|
||||
}
|
||||
Int2DAction<View> VIEW_SCROLL_BY = View::scrollBy;
|
||||
Int2DAction<View> VIEW_SCROLL_TO = View::scrollTo;
|
||||
Float2DAction<Canvas> CANVAS_TRANSLATE = Canvas::translate;
|
||||
<T> void set(T target, Int2DAction<T> action, int param);
|
||||
<T> void set(T target, Float2DAction<T> action, float param);
|
||||
float getPrimaryDirection(MotionEvent event, int pointerIndex);
|
||||
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
|
||||
int getMeasuredSize(View view);
|
||||
int getPrimarySize(Rect rect);
|
||||
float getPrimarySize(RectF rect);
|
||||
int getSecondaryDimension(View view);
|
||||
LauncherState.ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view);
|
||||
float getTranslationValue(LauncherState.ScaleAndTranslation scaleAndTranslation);
|
||||
FloatProperty<View> getPrimaryViewTranslate();
|
||||
FloatProperty<View> getSecondaryViewTranslate();
|
||||
void setPrimaryAndResetSecondaryTranslate(View view, float translation);
|
||||
float getViewCenterPosition(View view);
|
||||
int getPrimaryScroll(View view);
|
||||
float getPrimaryScale(View view);
|
||||
int getChildStart(View view);
|
||||
int getCenterForPage(View view, Rect insets);
|
||||
int getScrollOffsetStart(View view, Rect insets);
|
||||
int getScrollOffsetEnd(View view, Rect insets);
|
||||
SingleAxisSwipeDetector.Direction getOppositeSwipeDirection();
|
||||
int getShortEdgeLength(DeviceProfile dp);
|
||||
int getTaskDismissDirectionFactor();
|
||||
ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
|
||||
void setMaxScroll(AccessibilityEvent event, int maxScroll);
|
||||
boolean getRecentsRtlSetting(Resources resources);
|
||||
float getDegreesRotated();
|
||||
void offsetTaskRect(RectF rect, float value, int delta);
|
||||
int getPrimaryValue(int x, int y);
|
||||
int getSecondaryValue(int x, int y);
|
||||
void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll);
|
||||
/** Uses {@params pagedView}.getScroll[X|Y]() method for the secondary amount*/
|
||||
void delegateScrollTo(PagedView pagedView, int primaryScroll);
|
||||
void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y);
|
||||
void scrollerStartScroll(OverScroller scroller, int newPosition);
|
||||
CurveProperties getCurveProperties(PagedView pagedView, Rect insets);
|
||||
boolean isGoingUp(float displacement);
|
||||
|
||||
/**
|
||||
* Maps the velocity from the coordinate plane of the foreground app to that
|
||||
* of Launcher's (which now will always be portrait)
|
||||
*/
|
||||
void adjustFloatingIconStartVelocity(PointF velocity);
|
||||
|
||||
class CurveProperties {
|
||||
public final int scroll;
|
||||
public final int halfPageSize;
|
||||
public final int screenCenter;
|
||||
public final int halfScreenSize;
|
||||
|
||||
public CurveProperties(int scroll, int halfPageSize, int screenCenter, int halfScreenSize) {
|
||||
this.scroll = scroll;
|
||||
this.halfPageSize = halfPageSize;
|
||||
this.screenCenter = screenCenter;
|
||||
this.halfScreenSize = halfScreenSize;
|
||||
}
|
||||
}
|
||||
|
||||
class ChildBounds {
|
||||
|
||||
public final int primaryDimension;
|
||||
public final int secondaryDimension;
|
||||
public final int childPrimaryEnd;
|
||||
public final int childSecondaryEnd;
|
||||
|
||||
ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
|
||||
int childSecondaryEnd) {
|
||||
this.primaryDimension = primaryDimension;
|
||||
this.secondaryDimension = secondaryDimension;
|
||||
this.childPrimaryEnd = childPrimaryEnd;
|
||||
this.childSecondaryEnd = childSecondaryEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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.touch;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
|
||||
|
||||
public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
||||
|
||||
@Override
|
||||
public int getPrimaryValue(int x, int y) {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondaryValue(int x, int y) {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll) {
|
||||
pagedView.superScrollTo(primaryScroll, secondaryScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y) {
|
||||
pagedView.scrollTo(unboundedScroll + x, pagedView.getScrollY() + y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollerStartScroll(OverScroller scroller, int newPosition) {
|
||||
scroller.startScroll(newPosition - scroller.getCurrPos(), scroller.getCurrPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
|
||||
int scroll = pagedView.getScrollX();
|
||||
final int halfPageSize = pagedView.getNormalChildWidth() / 2;
|
||||
final int screenCenter = mInsets.left + pagedView.getPaddingLeft() + scroll + halfPageSize;
|
||||
final int halfScreenSize = pagedView.getMeasuredWidth() / 2;
|
||||
return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGoingUp(float displacement) {
|
||||
return displacement < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustFloatingIconStartVelocity(PointF velocity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delegateScrollTo(PagedView pagedView, int primaryScroll) {
|
||||
pagedView.superScrollTo(primaryScroll, pagedView.getScrollY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void set(T target, Int2DAction<T> action, int param) {
|
||||
action.call(target, param, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void set(T target, Float2DAction<T> action, float param) {
|
||||
action.call(target, param, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
|
||||
return event.getX(pointerIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
|
||||
return velocityTracker.getXVelocity(pointerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMeasuredSize(View view) {
|
||||
return view.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimarySize(Rect rect) {
|
||||
return rect.width();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimarySize(RectF rect) {
|
||||
return rect.width();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondaryDimension(View view) {
|
||||
return view.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
|
||||
float offscreenTranslationX = dp.widthPx - view.getPaddingStart();
|
||||
return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
|
||||
return scaleAndTranslation.translationX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatProperty<View> getPrimaryViewTranslate() {
|
||||
return VIEW_TRANSLATE_X;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatProperty<View> getSecondaryViewTranslate() {
|
||||
return VIEW_TRANSLATE_Y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryAndResetSecondaryTranslate(View view, float translation) {
|
||||
view.setTranslationX(translation);
|
||||
view.setTranslationY(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getViewCenterPosition(View view) {
|
||||
return view.getLeft() + view.getTranslationX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimaryScroll(View view) {
|
||||
return view.getScrollX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPrimaryScale(View view) {
|
||||
return view.getScaleX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
|
||||
event.setMaxScrollX(maxScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRecentsRtlSetting(Resources resources) {
|
||||
return !Utilities.isRtl(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDegreesRotated() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offsetTaskRect(RectF rect, float value, int displayRotation) {
|
||||
if (displayRotation == Surface.ROTATION_0) {
|
||||
rect.offset(value, 0);
|
||||
} else if (displayRotation == Surface.ROTATION_90) {
|
||||
rect.offset(0, -value);
|
||||
} else if (displayRotation == Surface.ROTATION_180) {
|
||||
rect.offset(-value, 0);
|
||||
} else {
|
||||
rect.offset(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildStart(View view) {
|
||||
return view.getLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCenterForPage(View view, Rect insets) {
|
||||
return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
|
||||
- insets.bottom - view.getPaddingBottom()) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollOffsetStart(View view, Rect insets) {
|
||||
return insets.left + view.getPaddingLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollOffsetEnd(View view, Rect insets) {
|
||||
return view.getWidth() - view.getPaddingRight() - insets.right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleAxisSwipeDetector.Direction getOppositeSwipeDirection() {
|
||||
return VERTICAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShortEdgeLength(DeviceProfile dp) {
|
||||
return dp.widthPx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaskDismissDirectionFactor() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
|
||||
boolean layoutChild) {
|
||||
final int childWidth = child.getMeasuredWidth();
|
||||
final int childRight = childStart + childWidth;
|
||||
final int childHeight = child.getMeasuredHeight();
|
||||
final int childTop = pageCenter - childHeight / 2;
|
||||
if (layoutChild) {
|
||||
child.layout(childStart, childTop, childRight, childTop + childHeight);
|
||||
}
|
||||
return new ChildBounds(childWidth, childHeight, childRight, childTop);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.touch;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||
|
||||
@Override
|
||||
public int getTaskDismissDirectionFactor() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRecentsRtlSetting(Resources resources) {
|
||||
return Utilities.isRtl(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offsetTaskRect(RectF rect, float value, int displayRotation) {
|
||||
if (displayRotation == Surface.ROTATION_0) {
|
||||
rect.offset(0, value);
|
||||
} else if (displayRotation == Surface.ROTATION_90) {
|
||||
rect.offset(value, 0);
|
||||
} else if (displayRotation == Surface.ROTATION_180) {
|
||||
rect.offset(0, -value);
|
||||
} else {
|
||||
rect.offset(-value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDegreesRotated() {
|
||||
return 270;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGoingUp(float displacement) {
|
||||
return displacement < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustFloatingIconStartVelocity(PointF velocity) {
|
||||
float oldX = velocity.x;
|
||||
float oldY = velocity.y;
|
||||
velocity.set(oldY, -oldX);
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,8 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector {
|
||||
|
||||
@Override
|
||||
protected void reportDragStartInternal(boolean recatch) {
|
||||
mListener.onDragStart(!recatch);
|
||||
float startDisplacement = mDir.extractDirection(mSubtractDisplacement);
|
||||
mListener.onDragStart(!recatch, startDisplacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,8 +166,13 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector {
|
||||
|
||||
/** Listener to receive updates on the swipe. */
|
||||
public interface Listener {
|
||||
/** @param start whether this was the original drag start, as opposed to a recatch. */
|
||||
void onDragStart(boolean start);
|
||||
/**
|
||||
* TODO(b/150256055) consolidate all the different onDrag() methods into one
|
||||
* @param start whether this was the original drag start, as opposed to a recatch.
|
||||
* @param startDisplacement the initial touch displacement for the primary direction as
|
||||
* given by by {@link Direction#extractDirection(PointF)}
|
||||
*/
|
||||
void onDragStart(boolean start, float startDisplacement);
|
||||
|
||||
boolean onDrag(float displacement);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -127,6 +129,18 @@ public class DefaultDisplay implements DisplayListener {
|
||||
|
||||
public final DisplayMetrics metrics;
|
||||
|
||||
@VisibleForTesting
|
||||
public Info(int id, int rotation, int singleFrameMs, Point realSize, Point smallestSize,
|
||||
Point largestSize, DisplayMetrics metrics) {
|
||||
this.id = id;
|
||||
this.rotation = rotation;
|
||||
this.singleFrameMs = singleFrameMs;
|
||||
this.realSize = realSize;
|
||||
this.smallestSize = smallestSize;
|
||||
this.largestSize = largestSize;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
private Info(Context context) {
|
||||
this(context.getSystemService(WindowManager.class).getDefaultDisplay());
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ public class DynamicResource implements ResourceProvider, PluginListener<Resourc
|
||||
return mContext.getResources().getColor(resId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(@DimenRes int resId) {
|
||||
return mContext.getResources().getFloat(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(ResourceProvider plugin, Context context) {
|
||||
mPlugin = plugin;
|
||||
|
||||
@@ -26,11 +26,13 @@ import android.view.ViewConfiguration;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
/**
|
||||
* Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
|
||||
* customization options.
|
||||
@@ -425,6 +427,7 @@ public class OverScroller {
|
||||
// Current state of the animation.
|
||||
private int mState = SPLINE;
|
||||
|
||||
private Context mContext;
|
||||
private SpringAnimation mSpring;
|
||||
|
||||
// Constant gravity value, used in the deceleration phase.
|
||||
@@ -500,6 +503,7 @@ public class OverScroller {
|
||||
}
|
||||
|
||||
SplineOverScroller(Context context) {
|
||||
mContext = context;
|
||||
mFinished = true;
|
||||
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
|
||||
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
|
||||
@@ -560,9 +564,12 @@ public class OverScroller {
|
||||
}
|
||||
mSpring = new SpringAnimation(this, SPRING_PROPERTY);
|
||||
|
||||
ResourceProvider rp = DynamicResource.provider(mContext);
|
||||
float stiffness = rp.getFloat(R.dimen.horizontal_spring_stiffness);
|
||||
float damping = rp.getFloat(R.dimen.horizontal_spring_damping_ratio);
|
||||
mSpring.setSpring(new SpringForce(mFinal)
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW)
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
||||
.setStiffness(stiffness)
|
||||
.setDampingRatio(damping));
|
||||
mSpring.setStartVelocity(velocity);
|
||||
mSpring.animateToFinalPosition(mFinal);
|
||||
mSpring.addEndListener((animation, canceled, value, velocity1) -> {
|
||||
|
||||
@@ -149,8 +149,7 @@ public abstract class AbstractSlideInView extends AbstractFloatingView
|
||||
/* SingleAxisSwipeDetector.Listener */
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
}
|
||||
public void onDragStart(boolean start, float startDisplacement) { }
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
@@ -93,6 +94,15 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAppWidget(RemoteViews remoteViews) {
|
||||
super.updateAppWidget(remoteViews);
|
||||
WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
|
||||
if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
|
||||
reInflate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
|
||||
int maxHeight) {
|
||||
|
||||
@@ -49,6 +49,9 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
public class WidgetManagerHelper {
|
||||
|
||||
//TODO: replace this with OPTION_APPWIDGET_RESTORE_COMPLETED b/63667276
|
||||
public static final String WIDGET_OPTION_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
|
||||
|
||||
final AppWidgetManager mAppWidgetManager;
|
||||
final Context mContext;
|
||||
|
||||
@@ -127,6 +130,14 @@ public class WidgetManagerHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a AppWidgetProvider has marked a widget restored
|
||||
*/
|
||||
public boolean isAppWidgetRestored(int appWidgetId) {
|
||||
return !WidgetsModel.GO_DISABLE_WIDGETS && mAppWidgetManager.getAppWidgetOptions(
|
||||
appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
|
||||
}
|
||||
|
||||
public static Map<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap(Context context) {
|
||||
if (WidgetsModel.GO_DISABLE_WIDGETS) {
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -51,6 +51,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
||||
public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
|
||||
new MainThreadInitializedObject<>(CustomWidgetManager::new);
|
||||
|
||||
private final Context mContext;
|
||||
/**
|
||||
* auto provider Id is an ever-increasing number that serves as the providerId whenever a new
|
||||
* custom widget has been connected.
|
||||
@@ -62,6 +63,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
||||
private Consumer<PackageUserKey> mWidgetRefreshCallback;
|
||||
|
||||
private CustomWidgetManager(Context context) {
|
||||
mContext = context;
|
||||
mPlugins = new SparseArray<>();
|
||||
mCustomWidgets = new ArrayList<>();
|
||||
mWidgetsIdMap = new SparseArray<>();
|
||||
@@ -69,6 +71,10 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
||||
.addPluginListener(this, CustomWidgetPlugin.class, true);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
|
||||
mPlugins.put(mAutoProviderId, plugin);
|
||||
|
||||
@@ -44,4 +44,9 @@ public interface ResourceProvider extends Plugin {
|
||||
* @see android.content.res.Resources#getColor(int)
|
||||
*/
|
||||
int getColor(int resId);
|
||||
|
||||
/**
|
||||
* @see android.content.res.Resources#getFloat(int)
|
||||
*/
|
||||
float getFloat(int resId);
|
||||
}
|
||||
|
||||
@@ -249,6 +249,10 @@ public class WidgetsModel {
|
||||
ComponentName providerName) {
|
||||
ArrayList<WidgetItem> widgetsList = mWidgetsList.get(
|
||||
new PackageItemInfo(providerName.getPackageName()));
|
||||
if (widgetsList == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (WidgetItem item : widgetsList) {
|
||||
if (item.componentName.equals(providerName)) {
|
||||
return item;
|
||||
|
||||
@@ -89,7 +89,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100, 100 - mTouchSlop);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +99,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100, 100 + mTouchSlop);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,7 +107,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener, never()).onDragStart(anyBoolean());
|
||||
verify(mMockListener, never()).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,7 +118,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,7 +129,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100 - mTouchSlop, 100);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,7 +140,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100 - mTouchSlop, 100);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,7 +151,7 @@ public class SingleAxisSwipeDetectorTest {
|
||||
mGenerator.put(0, 100, 100);
|
||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||
// TODO: actually calculate the following parameters and do exact value checks.
|
||||
verify(mMockListener).onDragStart(anyBoolean());
|
||||
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -34,10 +34,13 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Debug;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.uiautomator.By;
|
||||
@@ -68,6 +71,7 @@ import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.RuleChain;
|
||||
@@ -117,6 +121,14 @@ public abstract class AbstractLauncherUiTest {
|
||||
// so let's just mark the fact that the leak has happened.
|
||||
if (sDetectedActivityLeak == null) {
|
||||
sDetectedActivityLeak = violation.toString();
|
||||
try {
|
||||
Debug.dumpHprofData(
|
||||
getInstrumentation().getTargetContext()
|
||||
.getFilesDir().getPath()
|
||||
+ "/ActivityLeakHeapDump.hprof");
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "dumpHprofData failed", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
StrictMode.setVmPolicy(builder.build());
|
||||
@@ -126,18 +138,6 @@ public abstract class AbstractLauncherUiTest {
|
||||
public static void checkDetectedLeaks() {
|
||||
if (sDetectedActivityLeak != null && !sActivityLeakReported) {
|
||||
sActivityLeakReported = true;
|
||||
|
||||
final UiDevice device = UiDevice.getInstance(getInstrumentation());
|
||||
try {
|
||||
device.executeShellCommand(
|
||||
"am dumpheap "
|
||||
+ device.getLauncherPackageName()
|
||||
+ " "
|
||||
+ getInstrumentation().getTargetContext().getFilesDir().getPath()
|
||||
+ "/ActivityLeakHeapDump.hprof");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +215,21 @@ public abstract class AbstractLauncherUiTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final String launcherPackageName = mDevice.getLauncherPackageName();
|
||||
try {
|
||||
final Context context = InstrumentationRegistry.getContext();
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final PackageInfo launcherPackage = pm.getPackageInfo(launcherPackageName, 0);
|
||||
|
||||
if (!launcherPackage.versionName.equals("BuildFromAndroidStudio")) {
|
||||
Assert.assertEquals("Launcher version doesn't match tests version",
|
||||
pm.getPackageInfo(context.getPackageName(), 0).getLongVersionCode(),
|
||||
launcherPackage.getLongVersionCode());
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
mLauncherPid = 0;
|
||||
// Disable app tracker
|
||||
AppLaunchTracker.INSTANCE.initializeForTesting(new AppLaunchTracker());
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.launcher3.widget.WidgetHostViewLoader.getDefaultOption
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.appwidget.AppWidgetHost;
|
||||
@@ -33,6 +34,7 @@ import android.content.pm.PackageInstaller.SessionParams;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -41,6 +43,7 @@ import com.android.launcher3.LauncherAppWidgetHost;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.pm.InstallSessionHelper;
|
||||
import com.android.launcher3.tapl.Workspace;
|
||||
import com.android.launcher3.ui.AbstractLauncherUiTest;
|
||||
@@ -86,7 +89,8 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
||||
|
||||
// Clear all existing data
|
||||
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
|
||||
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
|
||||
LauncherSettings.Settings.call(mResolver,
|
||||
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -172,6 +176,26 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
||||
assertNotNull(AppWidgetManager.getInstance(mTargetContext)
|
||||
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
|
||||
LauncherSettings.Favorites.APPWIDGET_ID))));
|
||||
|
||||
// send OPTION_APPWIDGET_RESTORE_COMPLETED
|
||||
int appWidgetId = mCursor.getInt(
|
||||
mCursor.getColumnIndex(LauncherSettings.Favorites.APPWIDGET_ID));
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mTargetContext);
|
||||
|
||||
Bundle b = new Bundle();
|
||||
b.putBoolean(WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED, true);
|
||||
RemoteViews remoteViews = new RemoteViews(mTargetPackage, R.layout.appwidget_not_ready);
|
||||
appWidgetManager.updateAppWidgetOptions(appWidgetId, b);
|
||||
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
|
||||
|
||||
|
||||
// verify changes are reflected
|
||||
waitForLauncherCondition("App widget options did not update",
|
||||
l -> appWidgetManager.getAppWidgetOptions(appWidgetId).getBoolean(
|
||||
WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED));
|
||||
executeOnLauncher(l -> l.getAppWidgetHost().startListening());
|
||||
verifyWidgetPresent(info);
|
||||
assertNull(mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -254,6 +278,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
||||
|
||||
/**
|
||||
* Creates a LauncherAppWidgetInfo corresponding to {@param info}
|
||||
*
|
||||
* @param bindWidget if true the info is bound and a valid widgetId is assigned to
|
||||
* the LauncherAppWidgetInfo
|
||||
*/
|
||||
@@ -306,7 +331,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
||||
.keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName));
|
||||
return packages;
|
||||
});
|
||||
while(true) {
|
||||
while (true) {
|
||||
try {
|
||||
mTargetContext.getPackageManager().getPackageInfo(
|
||||
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
@@ -316,7 +341,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
||||
}
|
||||
}
|
||||
pkg = invalidPackage + count;
|
||||
count ++;
|
||||
count++;
|
||||
}
|
||||
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(10,
|
||||
new ComponentName(pkg, "com.test.widgetprovider"));
|
||||
|
||||
@@ -64,6 +64,7 @@ public class SimpleActivityRule<T extends Activity> implements TestRule {
|
||||
mBase.evaluate();
|
||||
} finally {
|
||||
app.unregisterActivityLifecycleCallbacks(this);
|
||||
mActivity = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user