Merging from ub-launcher3-master @ build 6269120
Bug:150504032 Test: manual, presubmit on the source branch x20/teams/android-launcher/merge/ub-launcher3-master_rvc-dev_6269120.html Change-Id: I17d430abf3804e30d5d76628c2a4e693d4f1d700
This commit is contained in:
@@ -71,6 +71,7 @@
|
|||||||
<application
|
<application
|
||||||
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||||
android:fullBackupOnly="true"
|
android:fullBackupOnly="true"
|
||||||
|
android:backupInForeground="true"
|
||||||
android:fullBackupContent="@xml/backupscheme"
|
android:fullBackupContent="@xml/backupscheme"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@drawable/ic_launcher_home"
|
android:icon="@drawable/ic_launcher_home"
|
||||||
|
|||||||
@@ -8,9 +8,26 @@ adamcohen@google.com
|
|||||||
hyunyoungs@google.com
|
hyunyoungs@google.com
|
||||||
mrcasey@google.com
|
mrcasey@google.com
|
||||||
sunnygoyal@google.com
|
sunnygoyal@google.com
|
||||||
|
awickham@google.com
|
||||||
twickham@google.com
|
twickham@google.com
|
||||||
winsonc@google.com
|
winsonc@google.com
|
||||||
zakcohen@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 FeatureFlags.java, globs = set noparent
|
||||||
per-file BaseFlags.java = sunnygoyal@google.com, adamcohen@google.com
|
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_SCREENSHOT_BUTTON = 25;
|
||||||
OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
|
OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
|
||||||
SELECT_MODE_CLOSE_BUTTON = 27;
|
SELECT_MODE_CLOSE_BUTTON = 27;
|
||||||
|
SELECT_MODE_ITEM = 28;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TipType {
|
enum TipType {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
android:resumeWhilePausing="true"
|
android:resumeWhilePausing="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity="${packageName}.launcher"
|
||||||
android:enabled="true">
|
android:enabled="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -93,6 +93,7 @@
|
|||||||
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||||
android:autoRemoveFromRecents="true"
|
android:autoRemoveFromRecents="true"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
|
android:taskAffinity="${packageName}.launcher"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
|
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
|
||||||
|
|||||||
@@ -28,4 +28,9 @@
|
|||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:outlineProvider="none"
|
android:outlineProvider="none"
|
||||||
android:theme="@style/HomeScreenElementTheme" />
|
android:theme="@style/HomeScreenElementTheme" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/overview_actions_view"
|
||||||
|
layout="@layout/overview_actions_holder" />
|
||||||
|
|
||||||
</com.android.quickstep.fallback.RecentsRootView>
|
</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
|
Copyright (C) 2017 The Android Open Source Project
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -14,17 +13,12 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<com.android.launcher3.InsettableFrameLayout
|
<com.android.quickstep.views.LauncherRecentsView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent"
|
||||||
<com.android.quickstep.views.LauncherRecentsView
|
android:accessibilityPaneTitle="@string/accessibility_recent_apps"
|
||||||
android:id="@+id/overview_panel_recents"
|
android:clipChildren="false"
|
||||||
android:theme="@style/HomeScreenElementTheme"
|
android:clipToPadding="false"
|
||||||
android:layout_width="match_parent"
|
android:theme="@style/HomeScreenElementTheme"
|
||||||
android:layout_height="match_parent"
|
android:visibility="invisible" />
|
||||||
android:clipChildren="false"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:accessibilityPaneTitle="@string/accessibility_recent_apps"
|
|
||||||
android:visibility="invisible" />
|
|
||||||
</com.android.launcher3.InsettableFrameLayout>
|
|
||||||
|
|||||||
@@ -35,25 +35,27 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/TextHeadline"
|
style="@style/TextHeadline"
|
||||||
|
android:id="@+id/hotseat_edu_heading"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="18dp"
|
android:layout_marginTop="18dp"
|
||||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||||
android:paddingRight="@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:textAlignment="center"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="20sp" />
|
android:textSize="20sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:id="@+id/hotseat_edu_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="18dp"
|
android:layout_marginTop="18dp"
|
||||||
android:layout_marginBottom="18dp"
|
android:layout_marginBottom="18dp"
|
||||||
android:fontFamily="roboto-medium"
|
android:fontFamily="roboto-medium"
|
||||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||||
android:paddingRight="@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:textAlignment="center"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
@@ -83,7 +85,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:text="@string/hotseat_migrate_accept"
|
android:text="@string/hotseat_edu_accept"
|
||||||
android:textAlignment="textEnd"
|
android:textAlignment="textEnd"
|
||||||
android:textColor="@android:color/white" />
|
android:textColor="@android:color/white" />
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/no_thanks"
|
android:id="@+id/no_thanks"
|
||||||
android:text="@string/hotseat_migrate_dismiss"
|
android:text="@string/hotseat_edu_dismiss"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:textColor="@android:color/white" />
|
android:textColor="@android:color/white" />
|
||||||
|
|||||||
@@ -23,10 +23,4 @@
|
|||||||
|
|
||||||
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
||||||
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
|
<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>
|
</resources>
|
||||||
+9
-3
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.launcher3;
|
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.BACKGROUND_APP;
|
||||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||||
import static com.android.launcher3.LauncherState.NORMAL;
|
import static com.android.launcher3.LauncherState.NORMAL;
|
||||||
@@ -39,6 +38,7 @@ import android.animation.AnimatorSet;
|
|||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.FloatProperty;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
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.AnimatorSetBuilder;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.anim.SpringAnimationBuilder;
|
import com.android.launcher3.anim.SpringAnimationBuilder;
|
||||||
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.quickstep.views.TaskView;
|
import com.android.quickstep.views.TaskView;
|
||||||
@@ -88,7 +89,8 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
|||||||
|
|
||||||
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
|
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
|
||||||
|
|
||||||
AppWindowAnimationHelper helper = new AppWindowAnimationHelper(mLauncher);
|
AppWindowAnimationHelper helper =
|
||||||
|
new AppWindowAnimationHelper(recentsView.getPagedViewOrientedState(), mLauncher);
|
||||||
anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets,
|
anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets,
|
||||||
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
|
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
|
||||||
|
|
||||||
@@ -197,7 +199,11 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
|||||||
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
|
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
|
||||||
RecentsView.CONTENT_ALPHA, values);
|
RecentsView.CONTENT_ALPHA, values);
|
||||||
case INDEX_RECENTS_TRANSLATE_X_ANIM:
|
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)
|
.setDampingRatio(0.8f)
|
||||||
.setStiffness(250)
|
.setStiffness(250)
|
||||||
.setValues(values)
|
.setValues(values)
|
||||||
|
|||||||
+20
-7
@@ -27,11 +27,15 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
|
import com.android.launcher3.CellLayout;
|
||||||
import com.android.launcher3.ItemInfo;
|
import com.android.launcher3.ItemInfo;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.Workspace;
|
||||||
import com.android.launcher3.WorkspaceItemInfo;
|
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.uioverrides.QuickstepLauncher;
|
||||||
import com.android.launcher3.util.ActivityTracker;
|
import com.android.launcher3.util.ActivityTracker;
|
||||||
import com.android.launcher3.util.Themes;
|
import com.android.launcher3.util.Themes;
|
||||||
@@ -61,16 +65,25 @@ public class HotseatEduController {
|
|||||||
mNotification = createNotification();
|
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();
|
ViewGroup hotseatVG = mLauncher.getHotseat().getShortcutsAndWidgets();
|
||||||
int workspacePageCount = mLauncher.getWorkspace().getPageCount();
|
|
||||||
for (int i = 0; i < hotseatVG.getChildCount(); i++) {
|
for (int i = 0; i < hotseatVG.getChildCount(); i++) {
|
||||||
View child = hotseatVG.getChildAt(i);
|
View child = hotseatVG.getChildAt(i);
|
||||||
ItemInfo tag = (ItemInfo) child.getTag();
|
ItemInfo tag = (ItemInfo) child.getTag();
|
||||||
mLauncher.getModelWriter().moveItemInDatabase(tag,
|
mLauncher.getModelWriter().moveItemInDatabase(tag,
|
||||||
LauncherSettings.Favorites.CONTAINER_DESKTOP, workspacePageCount, tag.screenId,
|
LauncherSettings.Favorites.CONTAINER_DESKTOP, toPage, tag.screenId, toRow);
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeNotification() {
|
void removeNotification() {
|
||||||
@@ -93,7 +106,7 @@ public class HotseatEduController {
|
|||||||
|
|
||||||
private void createNotificationChannel() {
|
private void createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
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;
|
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||||
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name,
|
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name,
|
||||||
importance);
|
importance);
|
||||||
@@ -104,8 +117,8 @@ public class HotseatEduController {
|
|||||||
Intent intent = new Intent(mLauncher.getApplicationContext(), mLauncher.getClass());
|
Intent intent = new Intent(mLauncher.getApplicationContext(), mLauncher.getClass());
|
||||||
intent = new NotificationHandler().addToIntent(intent);
|
intent = new NotificationHandler().addToIntent(intent);
|
||||||
|
|
||||||
CharSequence name = mLauncher.getString(R.string.hotseat_migrate_prompt_title);
|
CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title);
|
||||||
String description = mLauncher.getString(R.string.hotseat_migrate_prompt_content);
|
String description = mLauncher.getString(R.string.hotseat_edu_prompt_content);
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mLauncher,
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(mLauncher,
|
||||||
NOTIFICATION_CHANNEL_ID)
|
NOTIFICATION_CHANNEL_ID)
|
||||||
.setContentTitle(name)
|
.setContentTitle(name)
|
||||||
|
|||||||
+76
-21
@@ -26,6 +26,7 @@ import android.util.AttributeSet;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.launcher3.CellLayout;
|
import com.android.launcher3.CellLayout;
|
||||||
@@ -34,7 +35,9 @@ import com.android.launcher3.Insettable;
|
|||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.WorkspaceItemInfo;
|
import com.android.launcher3.WorkspaceItemInfo;
|
||||||
|
import com.android.launcher3.WorkspaceLayoutManager;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
@@ -49,12 +52,24 @@ import java.util.List;
|
|||||||
public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
|
public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
|
||||||
|
|
||||||
private static final int DEFAULT_CLOSE_DURATION = 200;
|
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 final Rect mInsets = new Rect();
|
||||||
private View mHotseatWrapper;
|
private View mHotseatWrapper;
|
||||||
private CellLayout mSampleHotseat;
|
private CellLayout mSampleHotseat;
|
||||||
|
private TextView mEduHeading;
|
||||||
|
private TextView mEduContent;
|
||||||
|
private Button mDismissBtn;
|
||||||
|
|
||||||
|
private int mMigrationMode = MIGRATE_SAME_PAGE;
|
||||||
|
|
||||||
public void setHotseatEduController(HotseatEduController hotseatEduController) {
|
public void setHotseatEduController(HotseatEduController hotseatEduController) {
|
||||||
mHotseatEduController = hotseatEduController;
|
mHotseatEduController = hotseatEduController;
|
||||||
@@ -78,6 +93,8 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
|
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
|
||||||
mSampleHotseat = findViewById(R.id.sample_prediction);
|
mSampleHotseat = findViewById(R.id.sample_prediction);
|
||||||
|
mEduHeading = findViewById(R.id.hotseat_edu_heading);
|
||||||
|
mEduContent = findViewById(R.id.hotseat_edu_content);
|
||||||
|
|
||||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||||
Rect padding = grid.getHotseatLayoutPadding();
|
Rect padding = grid.getHotseatLayoutPadding();
|
||||||
@@ -87,24 +104,27 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
|
mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
|
||||||
|
|
||||||
Button turnOnBtn = findViewById(R.id.turn_predictions_on);
|
Button turnOnBtn = findViewById(R.id.turn_predictions_on);
|
||||||
turnOnBtn.setOnClickListener(this::onMigrate);
|
turnOnBtn.setOnClickListener(this::onAccept);
|
||||||
|
|
||||||
Button learnMoreBtn = findViewById(R.id.no_thanks);
|
mDismissBtn = findViewById(R.id.no_thanks);
|
||||||
learnMoreBtn.setOnClickListener(this::onKeepDefault);
|
mDismissBtn.setOnClickListener(this::onDismiss);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMigrate(View v) {
|
private void onAccept(View v) {
|
||||||
if (mHotseatEduController == null) return;
|
if (mMigrationMode == MIGRATE_NO_MIGRATE || !mHotseatEduController.migrate()) {
|
||||||
|
onDismiss(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
handleClose(true);
|
handleClose(true);
|
||||||
mHotseatEduController.migrate();
|
|
||||||
mHotseatEduController.finishOnboarding();
|
mHotseatEduController.finishOnboarding();
|
||||||
logUserAction(true);
|
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) {
|
private void onDismiss(View v) {
|
||||||
if (mHotseatEduController == null) return;
|
|
||||||
Toast.makeText(getContext(), R.string.hotseat_no_migration, Toast.LENGTH_LONG).show();
|
Toast.makeText(getContext(), R.string.hotseat_no_migration, Toast.LENGTH_LONG).show();
|
||||||
mHotseatEduController.finishOnboarding();
|
mHotseatEduController.finishOnboarding();
|
||||||
logUserAction(false);
|
logUserAction(false);
|
||||||
@@ -148,6 +168,8 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
|
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
|
||||||
target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
|
target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
|
||||||
: HYBRID_HOTSEAT_CANCELED;
|
: HYBRID_HOTSEAT_CANCELED;
|
||||||
|
// encoding migration type on pageIndex
|
||||||
|
target.pageIndex = mMigrationMode;
|
||||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
||||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
||||||
}
|
}
|
||||||
@@ -161,6 +183,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
||||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animateOpen() {
|
private void animateOpen() {
|
||||||
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||||
return;
|
return;
|
||||||
@@ -183,17 +206,12 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
handleClose(false);
|
handleClose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Opens User education dialog with a list of suggested apps
|
protected int getScrimColor(Context context) {
|
||||||
*/
|
return FINAL_SCRIM_BG_COLOR;
|
||||||
public void show(List<WorkspaceItemInfo> predictions) {
|
}
|
||||||
if (getParent() != null
|
|
||||||
|| predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons) {
|
private void populatePreview(List<WorkspaceItemInfo> predictions) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
attachToContainer();
|
|
||||||
logOnBoardingSeen();
|
|
||||||
animateOpen();
|
|
||||||
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
||||||
WorkspaceItemInfo info = predictions.get(i);
|
WorkspaceItemInfo info = predictions.get(i);
|
||||||
PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
|
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
|
* Factory method for HotseatPredictionUserEdu dialog
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-2
@@ -80,10 +80,10 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
mMotionPauseDetector.clear();
|
mMotionPauseDetector.clear();
|
||||||
|
|
||||||
super.onDragStart(start);
|
super.onDragStart(start, startDisplacement);
|
||||||
|
|
||||||
if (handlingOverviewAnim()) {
|
if (handlingOverviewAnim()) {
|
||||||
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
|
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
|
||||||
|
|||||||
+1
-1
@@ -126,7 +126,7 @@ public class NavBarToHomeTouchController implements TouchController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
initCurrentAnimation();
|
initCurrentAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -94,8 +94,8 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
super.onDragStart(start);
|
super.onDragStart(start, startDisplacement);
|
||||||
|
|
||||||
mReachedOverview = false;
|
mReachedOverview = false;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -116,12 +116,13 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
|
|||||||
mLauncher = launcher;
|
mLauncher = launcher;
|
||||||
mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
|
mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
|
||||||
mShelfPeekAnim = mLauncher.getShelfPeekAnim();
|
mShelfPeekAnim = mLauncher.getShelfPeekAnim();
|
||||||
|
mRecentsView = mLauncher.getOverviewPanel();
|
||||||
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
|
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
|
||||||
mYRange = LayoutUtils.getShelfTrackingDistance(mLauncher, mLauncher.getDeviceProfile());
|
mYRange = LayoutUtils.getShelfTrackingDistance(
|
||||||
|
mLauncher, mLauncher.getDeviceProfile());
|
||||||
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
|
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
|
||||||
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
|
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
|
||||||
R.dimen.motion_pause_detector_min_displacement_from_app);
|
R.dimen.motion_pause_detector_min_displacement_from_app);
|
||||||
mRecentsView = mLauncher.getOverviewPanel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+2
-2
@@ -92,8 +92,8 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
super.onDragStart(start);
|
super.onDragStart(start, startDisplacement);
|
||||||
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
|
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
|
||||||
mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
|
mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
|
||||||
ActivityManagerWrapper.getInstance()
|
ActivityManagerWrapper.getInstance()
|
||||||
|
|||||||
+28
-9
@@ -36,6 +36,7 @@ import com.android.launcher3.Utilities;
|
|||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||||
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||||
import com.android.launcher3.util.FlingBlockCheck;
|
import com.android.launcher3.util.FlingBlockCheck;
|
||||||
@@ -77,7 +78,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
public TaskViewTouchController(T activity) {
|
public TaskViewTouchController(T activity) {
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
mRecentsView = activity.getOverviewPanel();
|
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() {
|
private boolean canInterceptTouch() {
|
||||||
@@ -105,6 +108,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
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) {
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
mNoIntercept = !canInterceptTouch();
|
mNoIntercept = !canInterceptTouch();
|
||||||
if (mNoIntercept) {
|
if (mNoIntercept) {
|
||||||
@@ -125,6 +132,11 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
TaskView view = mRecentsView.getTaskViewAt(i);
|
TaskView view = mRecentsView.getTaskViewAt(i);
|
||||||
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
|
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
|
||||||
.isEventOverView(view, ev)) {
|
.isEventOverView(view, ev)) {
|
||||||
|
// Disable swiping up and down if the task overlay is modal.
|
||||||
|
if (view.isTaskOverlayModal()) {
|
||||||
|
mTaskBeingDragged = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
mTaskBeingDragged = view;
|
mTaskBeingDragged = view;
|
||||||
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
|
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
|
||||||
// Don't allow swipe down to open if we don't support swipe up
|
// 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;
|
mPendingAnimation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||||
mCurrentAnimationIsGoingUp = goingUp;
|
mCurrentAnimationIsGoingUp = goingUp;
|
||||||
BaseDragLayer dl = mActivity.getDragLayer();
|
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) {
|
if (goingUp) {
|
||||||
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
|
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
|
||||||
true /* animateTaskView */, true /* removeTask */, maxDuration);
|
true /* animateTaskView */, true /* removeTask */, maxDuration);
|
||||||
|
|
||||||
mEndDisplacement = -mTaskBeingDragged.getHeight();
|
mEndDisplacement = -secondaryTaskDimension;
|
||||||
} else {
|
} else {
|
||||||
mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
|
mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
|
||||||
mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
|
mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
|
||||||
@@ -198,6 +213,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
|
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
|
||||||
mEndDisplacement = dl.getHeight() - mTempCords[1];
|
mEndDisplacement = dl.getHeight() - mTempCords[1];
|
||||||
}
|
}
|
||||||
|
mEndDisplacement *= verticalFactor;
|
||||||
|
|
||||||
if (mCurrentAnimation != null) {
|
if (mCurrentAnimation != null) {
|
||||||
mCurrentAnimation.setOnCancelRunnable(null);
|
mCurrentAnimation.setOnCancelRunnable(null);
|
||||||
@@ -211,9 +227,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
|
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||||
if (mCurrentAnimation == null) {
|
if (mCurrentAnimation == null) {
|
||||||
reInitAnimationController(mDetector.wasInitialTouchPositive());
|
reInitAnimationController(orientationHandler.isGoingUp(startDisplacement));
|
||||||
mDisplacementShift = 0;
|
mDisplacementShift = 0;
|
||||||
} else {
|
} else {
|
||||||
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
|
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
|
||||||
@@ -224,9 +241,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onDrag(float displacement) {
|
public boolean onDrag(float displacement) {
|
||||||
|
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||||
float totalDisplacement = displacement + mDisplacementShift;
|
float totalDisplacement = displacement + mDisplacementShift;
|
||||||
boolean isGoingUp =
|
boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
|
||||||
totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
|
orientationHandler.isGoingUp(totalDisplacement);
|
||||||
if (isGoingUp != mCurrentAnimationIsGoingUp) {
|
if (isGoingUp != mCurrentAnimationIsGoingUp) {
|
||||||
reInitAnimationController(isGoingUp);
|
reInitAnimationController(isGoingUp);
|
||||||
mFlingBlockCheck.blockFling();
|
mFlingBlockCheck.blockFling();
|
||||||
@@ -253,11 +271,12 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
|||||||
if (blockedFling) {
|
if (blockedFling) {
|
||||||
fling = false;
|
fling = false;
|
||||||
}
|
}
|
||||||
|
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||||
float progress = mCurrentAnimation.getProgressFraction();
|
float progress = mCurrentAnimation.getProgressFraction();
|
||||||
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
|
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
|
||||||
if (fling) {
|
if (fling) {
|
||||||
logAction = Touch.FLING;
|
logAction = Touch.FLING;
|
||||||
boolean goingUp = velocity < 0;
|
boolean goingUp = orientationHandler.isGoingUp(velocity);
|
||||||
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
|
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
|
||||||
} else {
|
} else {
|
||||||
logAction = Touch.SWIPE;
|
logAction = Touch.SWIPE;
|
||||||
|
|||||||
+2
-1
@@ -125,7 +125,8 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
|
|||||||
return anim;
|
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
|
// 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.
|
// 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.ACCEL_1_5;
|
||||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
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.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||||
@@ -32,6 +31,7 @@ import android.graphics.PointF;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.animation.Interpolator;
|
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.AnimationSuccessListener;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.graphics.RotationMode;
|
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.util.VibratorWrapper;
|
||||||
import com.android.launcher3.views.FloatingIconView;
|
import com.android.launcher3.views.FloatingIconView;
|
||||||
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
|
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";
|
private static final String TAG = "BaseSwipeUpHandler";
|
||||||
protected static final Rect TEMP_RECT = new Rect();
|
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;
|
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
|
||||||
|
|
||||||
// The distance needed to drag to reach the task size in recents.
|
// The distance needed to drag to reach the task size in recents.
|
||||||
protected int mTransitionDragLength;
|
protected int mTransitionDragLength;
|
||||||
// How much further we can drag past recents, as a factor of mTransitionDragLength.
|
// How much further we can drag past recents, as a factor of mTransitionDragLength.
|
||||||
protected float mDragLengthFactor = 1;
|
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 Context mContext;
|
||||||
protected final RecentsAnimationDeviceState mDeviceState;
|
protected final RecentsAnimationDeviceState mDeviceState;
|
||||||
@@ -94,7 +96,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
|||||||
protected final BaseActivityInterface<T> mActivityInterface;
|
protected final BaseActivityInterface<T> mActivityInterface;
|
||||||
protected final InputConsumerController mInputConsumer;
|
protected final InputConsumerController mInputConsumer;
|
||||||
|
|
||||||
protected final AppWindowAnimationHelper mAppWindowAnimationHelper;
|
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||||
protected final TransformParams mTransformParams = new TransformParams();
|
protected final TransformParams mTransformParams = new TransformParams();
|
||||||
|
|
||||||
// Shift in the range of [0, 1].
|
// Shift in the range of [0, 1].
|
||||||
@@ -123,6 +125,8 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
|||||||
protected boolean mCanceled;
|
protected boolean mCanceled;
|
||||||
protected int mFinishingRecentsAnimationForNewTaskId = -1;
|
protected int mFinishingRecentsAnimationForNewTaskId = -1;
|
||||||
|
|
||||||
|
private PagedViewOrientedState mOrientedState;
|
||||||
|
|
||||||
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
|
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
|
||||||
GestureState gestureState, InputConsumerController inputConsumer) {
|
GestureState gestureState, InputConsumerController inputConsumer) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@@ -132,20 +136,18 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
|||||||
mActivityInitListener =
|
mActivityInitListener =
|
||||||
mActivityInterface.createActivityInitListener(this::onActivityInit);
|
mActivityInterface.createActivityInitListener(this::onActivityInit);
|
||||||
mInputConsumer = inputConsumer;
|
mInputConsumer = inputConsumer;
|
||||||
|
|
||||||
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
|
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
|
||||||
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
|
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
|
||||||
|
|
||||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
||||||
.getDeviceProfile(mContext));
|
.getDeviceProfile(mContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void performHapticFeedback() {
|
protected void performHapticFeedback() {
|
||||||
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
|
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
|
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode navBarRotationMode) {
|
||||||
return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
|
return mRecentsView != null ? mRecentsView.getEventDispatcher(navBarRotationMode) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -158,12 +160,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
|||||||
} else {
|
} else {
|
||||||
float translation = Math.max(displacement, 0);
|
float translation = Math.max(displacement, 0);
|
||||||
shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
|
shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
|
||||||
if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
|
if (shift > mDragLengthFactorStartPullback) {
|
||||||
float pullbackProgress = Utilities.getProgress(shift,
|
float pullbackProgress = Utilities.getProgress(shift,
|
||||||
DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
|
mDragLengthFactorStartPullback, mDragLengthFactor);
|
||||||
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
|
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
|
||||||
shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
|
shift = mDragLengthFactorStartPullback + pullbackProgress
|
||||||
* (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
|
* (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.
|
// we otherwise use the minimized home bounds provided by the system.
|
||||||
mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
|
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);
|
mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
|
||||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||||
// We can drag all the way to the top of the screen.
|
// 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 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
|
* 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() {
|
protected void applyTransformUnchecked() {
|
||||||
float shift = mCurrentShift.value;
|
float shift = mCurrentShift.value;
|
||||||
float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
|
float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
|
||||||
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
|
float taskSize = getOrientationHandler()
|
||||||
mAppWindowAnimationHelper.getTargetRect().width());
|
.getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
|
||||||
|
float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
|
||||||
mTransformParams.setProgress(shift)
|
mTransformParams.setProgress(shift)
|
||||||
.setOffsetX(offsetX)
|
.setOffset(offset)
|
||||||
.setOffsetScale(offsetScale)
|
.setOffsetScale(offsetScale)
|
||||||
.setTargetSet(mRecentsAnimationTargets)
|
.setTargetSet(mRecentsAnimationTargets)
|
||||||
.setLauncherOnTop(true);
|
.setLauncherOnTop(true);
|
||||||
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) {
|
private float getTaskCurveScaleForOffset(float offset, float taskSize) {
|
||||||
float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + mPageSpacing;
|
int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
|
||||||
float interpolation = Math.min(1, offsetX / distanceToReachEdge);
|
float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
|
||||||
|
float interpolation = Math.min(1, offset / distanceToReachEdge);
|
||||||
return TaskView.getCurveScaleForInterpolation(interpolation);
|
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.
|
* 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.
|
* @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,
|
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||||
HomeAnimationFactory homeAnimationFactory) {
|
HomeAnimationFactory homeAnimationFactory) {
|
||||||
final RectF startRect = new RectF(
|
|
||||||
mAppWindowAnimationHelper.applyTransform(
|
|
||||||
mTransformParams.setProgress(startProgress)
|
|
||||||
.setTargetSet(mRecentsAnimationTargets)
|
|
||||||
.setLauncherOnTop(false)));
|
|
||||||
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
||||||
|
|
||||||
final View floatingView = homeAnimationFactory.getFloatingView();
|
final View floatingView = homeAnimationFactory.getFloatingView();
|
||||||
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
|
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) {
|
if (isFloatingIconView) {
|
||||||
FloatingIconView fiv = (FloatingIconView) floatingView;
|
FloatingIconView fiv = (FloatingIconView) floatingView;
|
||||||
anim.addAnimatorListener(fiv);
|
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
|
// 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.
|
// FolderIconView can be seen morphing into the icon shape.
|
||||||
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
|
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
|
||||||
|
final RectF rotatedRect = new RectF();
|
||||||
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
|
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -445,9 +485,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
|||||||
Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
|
Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
|
||||||
.setCurrentRect(currentRect)
|
.setCurrentRect(currentRect)
|
||||||
.setTargetAlpha(getWindowAlpha(progress));
|
.setTargetAlpha(getWindowAlpha(progress));
|
||||||
|
rotatedRect.set(currentRect);
|
||||||
if (isFloatingIconView) {
|
if (isFloatingIconView) {
|
||||||
|
RotationHelper.mapRectFromNormalOrientation(rotatedRect,
|
||||||
|
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
|
||||||
mTransformParams.setCornerRadius(endRadius * progress + startRadius
|
mTransformParams.setCornerRadius(endRadius * progress + startRadius
|
||||||
* (1f - progress));
|
* (1f - progress));
|
||||||
}
|
}
|
||||||
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -30,10 +30,11 @@ import android.graphics.RectF;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.BaseActivity;
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
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.launcher3.userevent.nano.LauncherLogProto;
|
||||||
import com.android.quickstep.fallback.FallbackRecentsView;
|
import com.android.quickstep.fallback.FallbackRecentsView;
|
||||||
import com.android.quickstep.util.ActivityInitListener;
|
import com.android.quickstep.util.ActivityInitListener;
|
||||||
|
|||||||
@@ -161,12 +161,12 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||||
|
super.onActivityInit(alreadyOnHome);
|
||||||
mActivity = mActivityInterface.getCreatedActivity();
|
mActivity = mActivityInterface.getCreatedActivity();
|
||||||
mRecentsView = mActivity.getOverviewPanel();
|
mRecentsView = mActivity.getOverviewPanel();
|
||||||
linkRecentsViewScroll();
|
linkRecentsViewScroll();
|
||||||
mRecentsView.setDisallowScrollToClearAll(true);
|
mRecentsView.setDisallowScrollToClearAll(true);
|
||||||
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
|
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
|
||||||
|
|
||||||
mRecentsView.setZoomProgress(1);
|
mRecentsView.setZoomProgress(1);
|
||||||
|
|
||||||
if (!mContinuingLastGesture) {
|
if (!mContinuingLastGesture) {
|
||||||
@@ -177,6 +177,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
|
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
|
||||||
|
mDeviceState.enableMultipleRegions(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +420,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
|||||||
this::createNewInputProxyHandler);
|
this::createNewInputProxyHandler);
|
||||||
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
|
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
|
||||||
anim.addAnimatorListener(endListener);
|
anim.addAnimatorListener(endListener);
|
||||||
anim.start(mEndVelocityPxPerMs);
|
anim.start(mContext, mEndVelocityPxPerMs);
|
||||||
mFinishAnimation = RunningWindowAnim.wrap(anim);
|
mFinishAnimation = RunningWindowAnim.wrap(anim);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -469,7 +470,8 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
|||||||
HomeAnimationFactory factory = new HomeAnimationFactory() {
|
HomeAnimationFactory factory = new HomeAnimationFactory() {
|
||||||
@Override
|
@Override
|
||||||
public RectF getWindowTargetRect() {
|
public RectF getWindowTargetRect() {
|
||||||
return HomeAnimationFactory.getDefaultWindowTargetRect(mDp);
|
return HomeAnimationFactory
|
||||||
|
.getDefaultWindowTargetRect(mRecentsView.getPagedOrientationHandler(), mDp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+30
-7
@@ -38,6 +38,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
@@ -54,6 +55,7 @@ import com.android.launcher3.LauncherState;
|
|||||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||||
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
import com.android.launcher3.views.FloatingIconView;
|
import com.android.launcher3.views.FloatingIconView;
|
||||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||||
@@ -78,6 +80,8 @@ import java.util.function.Predicate;
|
|||||||
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
|
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
|
||||||
|
|
||||||
private Runnable mAdjustInterpolatorsRunnable;
|
private Runnable mAdjustInterpolatorsRunnable;
|
||||||
|
private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
|
||||||
|
BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
|
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
|
@Override
|
||||||
public void onTransitionCancelled(boolean activityVisible) {
|
public void onTransitionCancelled(boolean activityVisible) {
|
||||||
Launcher launcher = getCreatedActivity();
|
Launcher launcher = getCreatedActivity();
|
||||||
@@ -176,7 +185,8 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
|||||||
if (canUseWorkspaceView) {
|
if (canUseWorkspaceView) {
|
||||||
return iconLocation;
|
return iconLocation;
|
||||||
} else {
|
} 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 scrollOffsetX = recentsView.getScrollOffset();
|
||||||
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
|
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
|
||||||
|
|
||||||
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
|
float fromTranslation = attached ? offscreenX - scrollOffsetX : 0;
|
||||||
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
|
float toTranslation = attached ? 0 : offscreenX - scrollOffsetX;
|
||||||
launcher.getStateManager()
|
launcher.getStateManager()
|
||||||
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
|
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
|
||||||
|
|
||||||
|
PagedOrientationHandler pagedOrientationHandler =
|
||||||
|
recentsView.getPagedViewOrientedState().getOrientationHandler();
|
||||||
if (!recentsView.isShown() && animate) {
|
if (!recentsView.isShown() && animate) {
|
||||||
recentsView.setTranslationX(fromTranslationX);
|
pagedOrientationHandler
|
||||||
|
.getPrimaryViewTranslate().set(recentsView, fromTranslation);
|
||||||
} else {
|
} else {
|
||||||
fromTranslationX = recentsView.getTranslationX();
|
fromTranslation =
|
||||||
|
pagedOrientationHandler.getPrimaryViewTranslate().get(recentsView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!animate) {
|
if (!animate) {
|
||||||
recentsView.setTranslationX(toTranslationX);
|
pagedOrientationHandler
|
||||||
|
.getPrimaryViewTranslate().set(recentsView, toTranslation);
|
||||||
} else {
|
} else {
|
||||||
launcher.getStateManager().createStateElementAnimation(
|
launcher.getStateManager().createStateElementAnimation(
|
||||||
INDEX_RECENTS_TRANSLATE_X_ANIM,
|
INDEX_RECENTS_TRANSLATE_X_ANIM,
|
||||||
fromTranslationX, toTranslationX).start();
|
fromTranslation, toTranslation).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
|
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);
|
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
|
@Override
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||||
|
super.onActivityInit(alreadyOnHome);
|
||||||
final T activity = mActivityInterface.getCreatedActivity();
|
final T activity = mActivityInterface.getCreatedActivity();
|
||||||
if (mActivity == activity) {
|
if (mActivity == activity) {
|
||||||
return true;
|
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)) {
|
if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
|
||||||
return LAST_TASK;
|
return LAST_TASK;
|
||||||
}
|
}
|
||||||
@@ -929,7 +940,8 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
|||||||
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
|
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
windowAnim.start(velocityPxPerMs);
|
getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
|
||||||
|
windowAnim.start(mContext, velocityPxPerMs);
|
||||||
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
|
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
|
||||||
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
||||||
mLauncherTransitionController = null;
|
mLauncherTransitionController = null;
|
||||||
|
|||||||
@@ -183,7 +183,8 @@ public final class RecentsActivity extends BaseRecentsActivity {
|
|||||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||||
AnimatorSet target = new AnimatorSet();
|
AnimatorSet target = new AnimatorSet();
|
||||||
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
|
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,
|
target.play(getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
|
||||||
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
|
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.launcher3.util.ResourceBasedOverride;
|
||||||
import com.android.quickstep.views.TaskThumbnailView;
|
import com.android.quickstep.views.TaskThumbnailView;
|
||||||
import com.android.quickstep.views.TaskView;
|
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.Task;
|
||||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||||
|
|
||||||
@@ -67,6 +68,13 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
|
public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
|
||||||
forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class);
|
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) {
|
public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
|
||||||
return new TaskOverlay();
|
return new TaskOverlay();
|
||||||
}
|
}
|
||||||
@@ -87,5 +95,12 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
* Called when the overlay is no longer used.
|
* Called when the overlay is no longer used.
|
||||||
*/
|
*/
|
||||||
public void reset() { }
|
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 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.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.MAIN_EXECUTOR;
|
||||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
|
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 androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
|
import com.android.launcher3.Launcher;
|
||||||
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
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.ActiveGestureLog;
|
||||||
import com.android.quickstep.util.AssistantUtilities;
|
import com.android.quickstep.util.AssistantUtilities;
|
||||||
import com.android.quickstep.util.ProtoTracer;
|
import com.android.quickstep.util.ProtoTracer;
|
||||||
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.systemui.plugins.OverscrollPlugin;
|
import com.android.systemui.plugins.OverscrollPlugin;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||||
@@ -449,6 +446,8 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
|
|
||||||
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
|
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
|
||||||
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
|
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
|
||||||
|
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||||
|
|
||||||
if (event.getAction() == ACTION_DOWN) {
|
if (event.getAction() == ACTION_DOWN) {
|
||||||
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
|
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
|
||||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||||
@@ -502,17 +501,32 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
|| previousGestureState.isRecentsAnimationRunning()
|
|| previousGestureState.isRecentsAnimationRunning()
|
||||||
? newBaseConsumer(previousGestureState, newGestureState, event)
|
? newBaseConsumer(previousGestureState, newGestureState, event)
|
||||||
: mResetGestureInputConsumer;
|
: mResetGestureInputConsumer;
|
||||||
|
// TODO(b/149880412): 2 button landscape mode is wrecked. Fixit!
|
||||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||||
|
handleOrientationSetup(base);
|
||||||
if (mDeviceState.canTriggerAssistantAction(event)) {
|
if (mDeviceState.canTriggerAssistantAction(event)) {
|
||||||
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
|
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()
|
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
|
||||||
&& (mOverscrollPlugin != null)
|
OverscrollPlugin plugin = null;
|
||||||
&& mOverscrollPlugin.isActive()) {
|
if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
|
||||||
// Put the overscroll gesture as higher priority than the Assistant or base gestures
|
TaskOverlayFactory factory =
|
||||||
base = new OverscrollInputConsumer(this, newGestureState, base, mInputMonitorCompat,
|
TaskOverlayFactory.INSTANCE.get(getApplicationContext());
|
||||||
mOverscrollPlugin);
|
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()) {
|
if (mDeviceState.isScreenPinningActive()) {
|
||||||
@@ -533,6 +547,22 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
return base;
|
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,
|
private InputConsumer newBaseConsumer(GestureState previousGestureState,
|
||||||
GestureState gestureState, MotionEvent event) {
|
GestureState gestureState, MotionEvent event) {
|
||||||
if (mDeviceState.isKeyguardShowingOccluded()) {
|
if (mDeviceState.isKeyguardShowingOccluded()) {
|
||||||
@@ -732,10 +762,18 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
FeatureFlags.dump(pw);
|
FeatureFlags.dump(pw);
|
||||||
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
|
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
|
||||||
mDeviceState.dump(pw);
|
mDeviceState.dump(pw);
|
||||||
mOverviewComponentObserver.dump(pw);
|
if (mOverviewComponentObserver != null) {
|
||||||
|
mOverviewComponentObserver.dump(pw);
|
||||||
|
}
|
||||||
|
if (mGestureState != null) {
|
||||||
|
mGestureState.dump(pw);
|
||||||
|
}
|
||||||
pw.println("TouchState:");
|
pw.println("TouchState:");
|
||||||
|
BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
|
||||||
|
: mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
|
||||||
boolean resumed = mOverviewComponentObserver != null
|
boolean resumed = mOverviewComponentObserver != null
|
||||||
&& mOverviewComponentObserver.getActivityInterface().isResumed();
|
&& mOverviewComponentObserver.getActivityInterface().isResumed();
|
||||||
|
pw.println(" createdOverviewActivity=" + createdOverviewActivity);
|
||||||
pw.println(" resumed=" + resumed);
|
pw.println(" resumed=" + resumed);
|
||||||
pw.println(" mConsumer=" + mConsumer.getName());
|
pw.println(" mConsumer=" + mConsumer.getName());
|
||||||
ActiveGestureLog.INSTANCE.dump("", pw);
|
ActiveGestureLog.INSTANCE.dump("", pw);
|
||||||
|
|||||||
+5
@@ -195,4 +195,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
|
|||||||
}
|
}
|
||||||
super.applyLoadPlan(tasks);
|
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
|
// Proxy events to recents view
|
||||||
if (mPassedWindowMoveSlop && mInteractionHandler != null
|
if (mPassedWindowMoveSlop && mInteractionHandler != null
|
||||||
&& !mRecentsViewDispatcher.hasConsumer()) {
|
&& !mRecentsViewDispatcher.hasConsumer()) {
|
||||||
mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
|
mRecentsViewDispatcher.setConsumer(mInteractionHandler
|
||||||
mNavBarPosition.getRotationMode()));
|
.getRecentsViewDispatcher(mNavBarPosition.getRotationMode()));
|
||||||
}
|
}
|
||||||
int edgeFlags = ev.getEdgeFlags();
|
int edgeFlags = ev.getEdgeFlags();
|
||||||
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
|
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
|
||||||
@@ -364,7 +364,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
|||||||
: mNavBarPosition.isLeftEdge()
|
: mNavBarPosition.isLeftEdge()
|
||||||
? -velocityX
|
? -velocityX
|
||||||
: velocityY;
|
: velocityY;
|
||||||
|
|
||||||
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
|
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
|
||||||
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
|
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
|
||||||
mDownPos);
|
mDownPos);
|
||||||
|
|||||||
+42
-20
@@ -15,12 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.quickstep.util;
|
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.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
@@ -28,6 +22,7 @@ import android.graphics.Matrix.ScaleToFit;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.view.Surface;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -37,6 +32,7 @@ import com.android.launcher3.LauncherState;
|
|||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
|
import com.android.launcher3.model.PagedViewOrientedState;
|
||||||
import com.android.launcher3.views.BaseDragLayer;
|
import com.android.launcher3.views.BaseDragLayer;
|
||||||
import com.android.quickstep.RemoteAnimationTargets;
|
import com.android.quickstep.RemoteAnimationTargets;
|
||||||
import com.android.quickstep.SystemUiProxy;
|
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.TransactionCompat;
|
||||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
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
|
* Utility class to handle window clip animation
|
||||||
*/
|
*/
|
||||||
@@ -82,6 +84,7 @@ public class AppWindowAnimationHelper {
|
|||||||
private final Rect mTmpRect = new Rect();
|
private final Rect mTmpRect = new Rect();
|
||||||
private final RectF mTmpRectF = new RectF();
|
private final RectF mTmpRectF = new RectF();
|
||||||
private final RectF mCurrentRectWithInsets = new RectF();
|
private final RectF mCurrentRectWithInsets = new RectF();
|
||||||
|
private PagedViewOrientedState mOrientedState;
|
||||||
// Corner radius of windows, in pixels
|
// Corner radius of windows, in pixels
|
||||||
private final float mWindowCornerRadius;
|
private final float mWindowCornerRadius;
|
||||||
// Corner radius of windows when they're in overview mode.
|
// 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 mTaskAlphaCallback = (t, a) -> a;
|
||||||
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
|
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
|
||||||
|
|
||||||
public AppWindowAnimationHelper(Context context) {
|
public AppWindowAnimationHelper(PagedViewOrientedState orientedState, Context context) {
|
||||||
|
mOrientedState = orientedState;
|
||||||
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
|
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
|
||||||
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
|
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
|
||||||
mTaskCornerRadius = TaskCornerRadius.get(context);
|
mTaskCornerRadius = TaskCornerRadius.get(context);
|
||||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
|
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AppWindowAnimationHelper(Context context) {
|
||||||
|
this(null, context);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||||
mSourceInsets.set(target.contentInsets);
|
mSourceInsets.set(target.contentInsets);
|
||||||
mSourceStackBounds.set(target.sourceContainerBounds);
|
mSourceStackBounds.set(target.sourceContainerBounds);
|
||||||
|
|
||||||
// TODO: Should sourceContainerBounds already have this offset?
|
// TODO: Should sourceContainerBounds already have this offset?
|
||||||
mSourceStackBounds.offsetTo(target.position.x, target.position.y);
|
mSourceStackBounds.offsetTo(target.position.x, target.position.y);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
|
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
|
// from the source rect. The difference between the target rect (scaled to the
|
||||||
// source rect) is the amount to clip on each edge.
|
// source rect) is the amount to clip on each edge.
|
||||||
RectF scaledTargetRect = new RectF(mTargetRect);
|
RectF scaledTargetRect = new RectF(mTargetRect);
|
||||||
Utilities.scaleRectFAboutCenter(scaledTargetRect,
|
float scale = getSrcToTargetScale();
|
||||||
mSourceRect.width() / mTargetRect.width());
|
Utilities.scaleRectFAboutCenter(scaledTargetRect, scale);
|
||||||
|
|
||||||
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
|
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
|
||||||
mSourceWindowClipInsets.set(
|
mSourceWindowClipInsets.set(
|
||||||
Math.max(scaledTargetRect.left, 0),
|
Math.max(scaledTargetRect.left, 0),
|
||||||
@@ -149,6 +157,16 @@ public class AppWindowAnimationHelper {
|
|||||||
mSourceRect.set(scaledTargetRect);
|
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) {
|
public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
|
||||||
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
|
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
|
||||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
|
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
|
||||||
@@ -221,7 +239,6 @@ public class AppWindowAnimationHelper {
|
|||||||
layer = Integer.MAX_VALUE;
|
layer = Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
|
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
|
||||||
// have to undo the scale.
|
// have to undo the scale.
|
||||||
surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
|
surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
|
||||||
@@ -237,11 +254,16 @@ public class AppWindowAnimationHelper {
|
|||||||
mTmpRectF.set(mTargetRect);
|
mTmpRectF.set(mTargetRect);
|
||||||
Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
|
Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
|
||||||
mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
|
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);
|
updateClipRect(params);
|
||||||
|
|
||||||
return mCurrentRect;
|
return mCurrentRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +362,7 @@ public class AppWindowAnimationHelper {
|
|||||||
* @return The source rect's scale and translation relative to the target rect.
|
* @return The source rect's scale and translation relative to the target rect.
|
||||||
*/
|
*/
|
||||||
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
|
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
|
||||||
float scale = mSourceRect.width() / mTargetRect.width();
|
float scale = getSrcToTargetScale();
|
||||||
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
|
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
|
||||||
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
|
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
|
||||||
}
|
}
|
||||||
@@ -390,7 +412,7 @@ public class AppWindowAnimationHelper {
|
|||||||
|
|
||||||
public static class TransformParams {
|
public static class TransformParams {
|
||||||
private float mProgress;
|
private float mProgress;
|
||||||
private float mOffsetX;
|
private float mOffset;
|
||||||
private float mOffsetScale;
|
private float mOffsetScale;
|
||||||
private @Nullable RectF mCurrentRect;
|
private @Nullable RectF mCurrentRect;
|
||||||
private float mTargetAlpha;
|
private float mTargetAlpha;
|
||||||
@@ -401,7 +423,7 @@ public class AppWindowAnimationHelper {
|
|||||||
|
|
||||||
public TransformParams() {
|
public TransformParams() {
|
||||||
mProgress = 0;
|
mProgress = 0;
|
||||||
mOffsetX = 0;
|
mOffset = 0;
|
||||||
mOffsetScale = 1;
|
mOffsetScale = 1;
|
||||||
mCurrentRect = null;
|
mCurrentRect = null;
|
||||||
mTargetAlpha = 1;
|
mTargetAlpha = 1;
|
||||||
@@ -453,8 +475,8 @@ public class AppWindowAnimationHelper {
|
|||||||
* the default), then offset the current rect by this amount after computing the rect based
|
* the default), then offset the current rect by this amount after computing the rect based
|
||||||
* on {@link #mProgress}.
|
* on {@link #mProgress}.
|
||||||
*/
|
*/
|
||||||
public TransformParams setOffsetX(float offsetX) {
|
public TransformParams setOffset(float offset) {
|
||||||
mOffsetX = offsetX;
|
mOffset = offset;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,8 +526,8 @@ public class AppWindowAnimationHelper {
|
|||||||
return mProgress;
|
return mProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getOffsetX() {
|
public float getOffset() {
|
||||||
return mOffsetX;
|
return mOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getOffsetScale() {
|
public float getOffsetScale() {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package com.android.quickstep.util;
|
package com.android.quickstep.util;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.content.res.Resources;
|
import android.content.Context;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
|
||||||
@@ -28,6 +28,8 @@ import androidx.dynamicanimation.animation.SpringForce;
|
|||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.FlingSpringAnim;
|
import com.android.launcher3.anim.FlingSpringAnim;
|
||||||
|
import com.android.launcher3.util.DynamicResource;
|
||||||
|
import com.android.systemui.plugins.ResourceProvider;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -103,7 +105,7 @@ public class RectFSpringAnim {
|
|||||||
private float mMinVisChange;
|
private float mMinVisChange;
|
||||||
private float mYOvershoot;
|
private float mYOvershoot;
|
||||||
|
|
||||||
public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) {
|
public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
|
||||||
mStartRect = startRect;
|
mStartRect = startRect;
|
||||||
mTargetRect = targetRect;
|
mTargetRect = targetRect;
|
||||||
mCurrentCenterX = mStartRect.centerX();
|
mCurrentCenterX = mStartRect.centerX();
|
||||||
@@ -111,8 +113,9 @@ public class RectFSpringAnim {
|
|||||||
mTrackingBottomY = startRect.bottom < targetRect.bottom;
|
mTrackingBottomY = startRect.bottom < targetRect.bottom;
|
||||||
mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
|
mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
|
||||||
|
|
||||||
mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change);
|
ResourceProvider rp = DynamicResource.provider(context);
|
||||||
mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot);
|
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
|
||||||
|
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTargetPositionChanged() {
|
public void onTargetPositionChanged() {
|
||||||
@@ -137,7 +140,12 @@ public class RectFSpringAnim {
|
|||||||
mAnimatorListeners.add(animatorListener);
|
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.
|
// Only tell caller that we ended if both x and y animations have ended.
|
||||||
OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
|
OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
|
||||||
mRectXAnimEnded = true;
|
mRectXAnimEnded = true;
|
||||||
@@ -152,7 +160,7 @@ public class RectFSpringAnim {
|
|||||||
float endX = mTargetRect.centerX();
|
float endX = mTargetRect.centerX();
|
||||||
float minXValue = Math.min(startX, endX);
|
float minXValue = Math.min(startX, endX);
|
||||||
float maxXValue = Math.max(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);
|
velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);
|
||||||
|
|
||||||
float startVelocityY = velocityPxPerMs.y * 1000;
|
float startVelocityY = velocityPxPerMs.y * 1000;
|
||||||
@@ -162,14 +170,18 @@ public class RectFSpringAnim {
|
|||||||
float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
|
float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
|
||||||
float minYValue = Math.min(startY, endY - mYOvershoot);
|
float minYValue = Math.min(startY, endY - mYOvershoot);
|
||||||
float maxYValue = Math.max(startY, endY);
|
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);
|
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
|
||||||
|
|
||||||
float minVisibleChange = Math.abs(1f / mStartRect.height());
|
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)
|
mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
|
||||||
.setSpring(new SpringForce(1f)
|
.setSpring(new SpringForce(1f)
|
||||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
.setDampingRatio(damping)
|
||||||
.setStiffness(SpringForce.STIFFNESS_LOW))
|
.setStiffness(stiffness))
|
||||||
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
|
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
|
||||||
.setMaxValue(1f)
|
.setMaxValue(1f)
|
||||||
.setMinimumVisibleChange(minVisibleChange)
|
.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.PropertySetter;
|
||||||
import com.android.launcher3.anim.SpringAnimationBuilder;
|
import com.android.launcher3.anim.SpringAnimationBuilder;
|
||||||
import com.android.launcher3.graphics.OverviewScrim;
|
import com.android.launcher3.graphics.OverviewScrim;
|
||||||
|
import com.android.launcher3.util.DynamicResource;
|
||||||
import com.android.quickstep.views.RecentsView;
|
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,
|
* 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 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 mVelocity;
|
||||||
private final float mSpringTransY;
|
private final float mSpringTransY;
|
||||||
|
|
||||||
@@ -177,9 +176,12 @@ public class StaggeredWorkspaceAnim {
|
|||||||
|
|
||||||
v.setTranslationY(mSpringTransY);
|
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)
|
ObjectAnimator springTransY = new SpringAnimationBuilder<>(v, VIEW_TRANSLATE_Y)
|
||||||
.setStiffness(STIFFNESS)
|
.setStiffness(stiffness)
|
||||||
.setDampingRatio(DAMPING_RATIO)
|
.setDampingRatio(damping)
|
||||||
.setMinimumVisibleChange(1f)
|
.setMinimumVisibleChange(1f)
|
||||||
.setEndValue(0)
|
.setEndValue(0)
|
||||||
.setStartVelocity(mVelocity)
|
.setStartVelocity(mVelocity)
|
||||||
|
|||||||
+32
-10
@@ -21,7 +21,7 @@ import android.util.AttributeSet;
|
|||||||
import android.util.Property;
|
import android.util.Property;
|
||||||
import android.widget.Button;
|
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.PageCallbacks;
|
||||||
import com.android.quickstep.views.RecentsView.ScrollState;
|
import com.android.quickstep.views.RecentsView.ScrollState;
|
||||||
|
|
||||||
@@ -44,21 +44,26 @@ public class ClearAllButton extends Button implements PageCallbacks {
|
|||||||
private float mContentAlpha = 1;
|
private float mContentAlpha = 1;
|
||||||
private float mVisibilityAlpha = 1;
|
private float mVisibilityAlpha = 1;
|
||||||
|
|
||||||
private final boolean mIsRtl;
|
private boolean mIsRtl;
|
||||||
|
|
||||||
private int mScrollOffset;
|
private int mScrollOffset;
|
||||||
|
private RecentsView mParent;
|
||||||
|
|
||||||
public ClearAllButton(Context context, AttributeSet attrs) {
|
public ClearAllButton(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
mIsRtl = Utilities.isRtl(context.getResources());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
mScrollOffset = mIsRtl ? mParent.getPaddingRight() / 2 : - mParent.getPaddingLeft() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
RecentsView parent = (RecentsView) getParent();
|
@Override
|
||||||
mScrollOffset = mIsRtl ? parent.getPaddingRight() / 2 : - parent.getPaddingLeft() / 2;
|
protected void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
mParent = (RecentsView) getParent();
|
||||||
|
mIsRtl = !mParent.getPagedOrientationHandler().getRecentsRtlSetting(getResources());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
public void setVisibilityAlpha(float alpha) {
|
||||||
if (mVisibilityAlpha != alpha) {
|
if (mVisibilityAlpha != alpha) {
|
||||||
mVisibilityAlpha = alpha;
|
mVisibilityAlpha = alpha;
|
||||||
@@ -82,14 +102,16 @@ public class ClearAllButton extends Button implements PageCallbacks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageScroll(ScrollState scrollState) {
|
public void onPageScroll(ScrollState scrollState) {
|
||||||
float width = getWidth();
|
PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
|
||||||
if (width == 0) {
|
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
|
||||||
|
if (orientationSize == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float shift = Math.min(scrollState.scrollFromEdge, width);
|
float shift = Math.min(scrollState.scrollFromEdge, orientationSize);
|
||||||
setTranslationX(mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift));
|
float translation = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
|
||||||
mScrollAlpha = 1 - shift / width;
|
orientationHandler.setPrimaryAndResetSecondaryTranslate(this, translation);
|
||||||
|
mScrollAlpha = 1 - shift / orientationSize;
|
||||||
updateAlpha();
|
updateAlpha();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-10
@@ -42,10 +42,12 @@ import com.android.launcher3.Hotseat;
|
|||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.LauncherStateManager.StateListener;
|
import com.android.launcher3.LauncherStateManager.StateListener;
|
||||||
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||||
|
import com.android.launcher3.states.RotationHelper;
|
||||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||||
import com.android.launcher3.util.TraceHelper;
|
import com.android.launcher3.util.TraceHelper;
|
||||||
import com.android.launcher3.views.ScrimView;
|
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) {
|
public LauncherRecentsView(Context context) {
|
||||||
this(context, null);
|
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.
|
* @return The translationX to apply to this view so that the first task is just offscreen.
|
||||||
*/
|
*/
|
||||||
public float getOffscreenTranslationX(float recentsScale) {
|
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.
|
// Offset since scale pushes tasks outwards.
|
||||||
getTaskSize(sTempRect);
|
getTaskSize(sTempRect);
|
||||||
int taskWidth = sTempRect.width();
|
int taskSize = mOrientationHandler.getPrimarySize(sTempRect);
|
||||||
offscreenX += taskWidth * (recentsScale - 1) / 2;
|
offscreen += taskSize * (recentsScale - 1) / 2;
|
||||||
if (mRunningTaskTileHidden) {
|
if (mRunningTaskTileHidden) {
|
||||||
// The first task is hidden, so offset by its width.
|
// The first task is hidden, so offset by its width.
|
||||||
offscreenX -= (taskWidth + getPageSpacing()) * recentsScale;
|
offscreen -= (taskSize + getPageSpacing()) * recentsScale;
|
||||||
}
|
}
|
||||||
if (isRtl()) {
|
if (isRtl()) {
|
||||||
offscreenX = -offscreenX;
|
offscreen = -offscreen;
|
||||||
}
|
}
|
||||||
return offscreenX;
|
return offscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -276,6 +284,11 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
|||||||
return mTransformParams;
|
return mTransformParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean supportsVerticalLandscape() {
|
||||||
|
return PagedView.sFlagForcedRotation;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
super.reset();
|
super.reset();
|
||||||
@@ -329,6 +342,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener(
|
PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener(
|
||||||
mRecentsExtraCardPluginListener, RecentsExtraCard.class);
|
mRecentsExtraCardPluginListener, RecentsExtraCard.class);
|
||||||
|
mActivity.getRotationHelper().addForcedRotationCallback(mForcedRotationChangedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -336,22 +350,23 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
|||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(
|
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(
|
||||||
mRecentsExtraCardPluginListener);
|
mRecentsExtraCardPluginListener);
|
||||||
|
mActivity.getRotationHelper().removeForcedRotationCallback(mForcedRotationChangedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int computeMinScrollX() {
|
protected int computeMinScroll() {
|
||||||
if (canComputeScrollX() && !mIsRtl) {
|
if (canComputeScrollX() && !mIsRtl) {
|
||||||
return computeScrollX();
|
return computeScrollX();
|
||||||
}
|
}
|
||||||
return super.computeMinScrollX();
|
return super.computeMinScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int computeMaxScrollX() {
|
protected int computeMaxScroll() {
|
||||||
if (canComputeScrollX() && mIsRtl) {
|
if (canComputeScrollX() && mIsRtl) {
|
||||||
return computeScrollX();
|
return computeScrollX();
|
||||||
}
|
}
|
||||||
return super.computeMaxScrollX();
|
return super.computeMaxScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canComputeScrollX() {
|
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.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
|
||||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
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_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.EDGE_NAV_BAR;
|
||||||
import static com.android.launcher3.Utilities.squaredHypot;
|
import static com.android.launcher3.Utilities.squaredHypot;
|
||||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
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.ACCEL_2;
|
||||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
||||||
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
|
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.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
@@ -66,11 +65,14 @@ import android.text.StaticLayout;
|
|||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.FloatProperty;
|
import android.util.FloatProperty;
|
||||||
|
import android.util.Property;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.view.OrientationEventListener;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewDebug;
|
import android.view.ViewDebug;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -80,26 +82,32 @@ import android.view.animation.Interpolator;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.dynamicanimation.animation.SpringForce;
|
|
||||||
|
|
||||||
import com.android.launcher3.BaseActivity;
|
import com.android.launcher3.BaseActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Insettable;
|
import com.android.launcher3.Insettable;
|
||||||
|
import com.android.launcher3.InsettableFrameLayout;
|
||||||
import com.android.launcher3.InvariantDeviceProfile;
|
import com.android.launcher3.InvariantDeviceProfile;
|
||||||
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.PagedView;
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.PropertyListBuilder;
|
import com.android.launcher3.anim.PropertyListBuilder;
|
||||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
|
import com.android.launcher3.dragndrop.DragLayer;
|
||||||
import com.android.launcher3.graphics.RotationMode;
|
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;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
import com.android.launcher3.util.ComponentKey;
|
||||||
|
import com.android.launcher3.util.DynamicResource;
|
||||||
import com.android.launcher3.util.OverScroller;
|
import com.android.launcher3.util.OverScroller;
|
||||||
import com.android.launcher3.util.PendingAnimation;
|
import com.android.launcher3.util.PendingAnimation;
|
||||||
import com.android.launcher3.util.Themes;
|
import com.android.launcher3.util.Themes;
|
||||||
@@ -108,12 +116,14 @@ import com.android.quickstep.RecentsAnimationController;
|
|||||||
import com.android.quickstep.RecentsAnimationTargets;
|
import com.android.quickstep.RecentsAnimationTargets;
|
||||||
import com.android.quickstep.RecentsModel;
|
import com.android.quickstep.RecentsModel;
|
||||||
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
||||||
|
import com.android.quickstep.SysUINavigationMode;
|
||||||
import com.android.quickstep.SystemUiProxy;
|
import com.android.quickstep.SystemUiProxy;
|
||||||
import com.android.quickstep.TaskThumbnailCache;
|
import com.android.quickstep.TaskThumbnailCache;
|
||||||
import com.android.quickstep.TaskUtils;
|
import com.android.quickstep.TaskUtils;
|
||||||
import com.android.quickstep.ViewUtils;
|
import com.android.quickstep.ViewUtils;
|
||||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||||
import com.android.quickstep.util.LayoutUtils;
|
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.IPinnedStackAnimationListener;
|
||||||
import com.android.systemui.shared.recents.model.Task;
|
import com.android.systemui.shared.recents.model.Task;
|
||||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
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 RecentsAnimationController mRecentsAnimationController;
|
||||||
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
||||||
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||||
@@ -198,7 +210,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
private boolean mDwbToastShown;
|
private boolean mDwbToastShown;
|
||||||
protected boolean mDisallowScrollToClearAll;
|
protected boolean mDisallowScrollToClearAll;
|
||||||
private boolean mOverlayEnabled;
|
private boolean mOverlayEnabled;
|
||||||
private boolean mFreezeViewVisibility;
|
protected boolean mFreezeViewVisibility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Call reloadIdNeeded in onTaskStackChanged.
|
* TODO: Call reloadIdNeeded in onTaskStackChanged.
|
||||||
@@ -268,15 +280,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final IPinnedStackAnimationListener mIPinnedStackAnimationListener =
|
private final PinnedStackAnimationListener mIPinnedStackAnimationListener =
|
||||||
new IPinnedStackAnimationListener.Stub() {
|
new PinnedStackAnimationListener();
|
||||||
@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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Used to keep track of the last requested task list id, so that we do not request to load the
|
// 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
|
// 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
|
// Keeps track of the index where the first TaskView should be
|
||||||
private int mTaskViewStartIndex = 0;
|
private int mTaskViewStartIndex = 0;
|
||||||
|
private View mActionsView;
|
||||||
|
private boolean mGestureRunning = false;
|
||||||
|
|
||||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||||
(inMultiWindowMode) -> {
|
(inMultiWindowMode) -> {
|
||||||
@@ -340,7 +347,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
mActivity = (T) BaseActivity.fromContext(context);
|
mActivity = (T) BaseActivity.fromContext(context);
|
||||||
mModel = RecentsModel.INSTANCE.get(context);
|
mModel = RecentsModel.INSTANCE.get(context);
|
||||||
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
|
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
|
||||||
mTempAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
|
mTempAppWindowAnimationHelper =
|
||||||
|
new AppWindowAnimationHelper(getPagedViewOrientedState(), context);
|
||||||
|
|
||||||
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
|
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
|
||||||
.inflate(R.layout.overview_clear_all_button, this, false);
|
.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 */,
|
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
|
||||||
10 /* initial size */);
|
10 /* initial size */);
|
||||||
|
|
||||||
mIsRtl = !Utilities.isRtl(getResources());
|
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
|
||||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||||
mTaskTopMargin = getResources()
|
mTaskTopMargin = getResources()
|
||||||
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
.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);
|
.getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
updateEmptyMessage();
|
updateEmptyMessage();
|
||||||
|
disableMultipleLayoutRotations(!supportsVerticalLandscape());
|
||||||
|
|
||||||
// Initialize quickstep specific cache params here, as this is constructed only once
|
// Initialize quickstep specific cache params here, as this is constructed only once
|
||||||
mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
|
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() {
|
public OverScroller getScroller() {
|
||||||
@@ -451,8 +476,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
|
mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
|
||||||
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
||||||
mIdp.addOnChangeListener(this);
|
mIdp.addOnChangeListener(this);
|
||||||
|
mIPinnedStackAnimationListener.setActivity(mActivity);
|
||||||
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
|
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
|
||||||
mIPinnedStackAnimationListener);
|
mIPinnedStackAnimationListener);
|
||||||
|
addActionsView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -466,6 +493,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
|
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
|
||||||
mIdp.removeOnChangeListener(this);
|
mIdp.removeOnChangeListener(this);
|
||||||
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
|
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
|
||||||
|
mIPinnedStackAnimationListener.setActivity(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -496,6 +524,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setOverviewStateEnabled(boolean enabled) {
|
public void setOverviewStateEnabled(boolean enabled) {
|
||||||
|
if (supportsVerticalLandscape() && mOrientationListener.canDetectOrientation()) {
|
||||||
|
if (enabled) {
|
||||||
|
mOrientationListener.enable();
|
||||||
|
} else {
|
||||||
|
mOrientationListener.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
mOverviewStateEnabled = enabled;
|
mOverviewStateEnabled = enabled;
|
||||||
updateTaskStackListenerState();
|
updateTaskStackListenerState();
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
@@ -573,6 +608,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
|
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) {
|
protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -599,6 +641,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
if (getTaskViewCount() != requiredTaskCount) {
|
if (getTaskViewCount() != requiredTaskCount) {
|
||||||
if (indexOfChild(mClearAllButton) != -1) {
|
if (indexOfChild(mClearAllButton) != -1) {
|
||||||
removeView(mClearAllButton);
|
removeView(mClearAllButton);
|
||||||
|
hideActionsView();
|
||||||
}
|
}
|
||||||
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
|
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
|
||||||
addView(mTaskViewPool.getView());
|
addView(mTaskViewPool.getView());
|
||||||
@@ -608,6 +651,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
if (requiredTaskCount > 0) {
|
if (requiredTaskCount > 0) {
|
||||||
addView(mClearAllButton);
|
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 int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
|
||||||
final Task task = tasks.get(i);
|
final Task task = tasks.get(i);
|
||||||
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
||||||
taskView.bind(task);
|
taskView.bind(task, mLayoutRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNextPage == INVALID_PAGE) {
|
if (mNextPage == INVALID_PAGE) {
|
||||||
@@ -647,6 +691,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
if (indexOfChild(mClearAllButton) != -1) {
|
if (indexOfChild(mClearAllButton) != -1) {
|
||||||
removeView(mClearAllButton);
|
removeView(mClearAllButton);
|
||||||
}
|
}
|
||||||
|
hideActionsView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTaskViewCount() {
|
public int getTaskViewCount() {
|
||||||
@@ -748,19 +793,21 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
|
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int scrollX = getScrollX();
|
CurveProperties curveProperties = mOrientationHandler
|
||||||
final int halfPageWidth = getNormalChildWidth() / 2;
|
.getCurveProperties(this, mInsets);
|
||||||
final int screenCenter = mInsets.left + getPaddingLeft() + scrollX + halfPageWidth;
|
int scroll = curveProperties.scroll;
|
||||||
final int halfScreenWidth = getMeasuredWidth() / 2;
|
final int halfPageSize = curveProperties.halfPageSize;
|
||||||
|
final int screenCenter = curveProperties.screenCenter;
|
||||||
|
final int halfScreenSize = curveProperties.halfScreenSize;
|
||||||
final int pageSpacing = mPageSpacing;
|
final int pageSpacing = mPageSpacing;
|
||||||
mScrollState.scrollFromEdge = mIsRtl ? scrollX : (mMaxScrollX - scrollX);
|
mScrollState.scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
|
||||||
|
|
||||||
final int pageCount = getPageCount();
|
final int pageCount = getPageCount();
|
||||||
for (int i = 0; i < pageCount; i++) {
|
for (int i = 0; i < pageCount; i++) {
|
||||||
View page = getPageAt(i);
|
View page = getPageAt(i);
|
||||||
float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth;
|
float pageCenter = mOrientationHandler.getViewCenterPosition(page) + halfPageSize;
|
||||||
float distanceFromScreenCenter = screenCenter - pageCenter;
|
float distanceFromScreenCenter = screenCenter - pageCenter;
|
||||||
float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
|
float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
|
||||||
mScrollState.linearInterpolation = Math.min(1,
|
mScrollState.linearInterpolation = Math.min(1,
|
||||||
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
|
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
|
||||||
((PageCallbacks) page).onPageScroll(mScrollState);
|
((PageCallbacks) page).onPageScroll(mScrollState);
|
||||||
@@ -892,6 +939,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
setEnableDrawingLiveTile(false);
|
setEnableDrawingLiveTile(false);
|
||||||
setRunningTaskHidden(true);
|
setRunningTaskHidden(true);
|
||||||
setRunningTaskIconScaledDown(true);
|
setRunningTaskIconScaledDown(true);
|
||||||
|
mGestureRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -908,6 +956,47 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
setSwipeDownShouldLaunchApp(true);
|
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.
|
* 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);
|
setRunningTaskHidden(false);
|
||||||
animateUpRunningTaskIconScale();
|
animateUpRunningTaskIconScale();
|
||||||
|
mGestureRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -936,6 +1026,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
addView(taskView, mTaskViewStartIndex);
|
addView(taskView, mTaskViewStartIndex);
|
||||||
if (wasEmpty) {
|
if (wasEmpty) {
|
||||||
addView(mClearAllButton);
|
addView(mClearAllButton);
|
||||||
|
showActionsView();
|
||||||
}
|
}
|
||||||
// The temporary running task is only used for the duration between the start of the
|
// The temporary running task is only used for the duration between the start of the
|
||||||
// gesture and the task list is loaded and applied
|
// 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,
|
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
|
||||||
false, true, false, false, new ActivityManager.TaskDescription(), 0,
|
false, true, false, false, new ActivityManager.TaskDescription(), 0,
|
||||||
new ComponentName("", ""), false);
|
new ComponentName("", ""), false);
|
||||||
taskView.bind(mTmpRunningTask);
|
taskView.bind(mTmpRunningTask, mLayoutRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
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) {
|
private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
|
||||||
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
|
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) {
|
if (UNSTABLE_SPRINGS.get() && taskView instanceof TaskView) {
|
||||||
addAnim(new SpringObjectAnimator<>(taskView, VIEW_TRANSLATE_Y,
|
ResourceProvider rp = DynamicResource.provider(mActivity);
|
||||||
MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
|
float dampingRatio = rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio);
|
||||||
SpringForce.STIFFNESS_MEDIUM,
|
float stiffness = rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness);
|
||||||
0, -taskView.getHeight()),
|
|
||||||
|
addAnim(new SpringObjectAnimator<>(taskView, secondaryViewTranslate,
|
||||||
|
MIN_VISIBLE_CHANGE_PIXELS, dampingRatio,
|
||||||
|
stiffness, 0, verticalFactor * secondaryTaskDimension),
|
||||||
duration, LINEAR, anim);
|
duration, LINEAR, anim);
|
||||||
} else {
|
} else {
|
||||||
addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
|
addAnim(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
|
||||||
duration, LINEAR, anim);
|
verticalFactor * secondaryTaskDimension), duration, LINEAR, anim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1158,11 +1256,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
int[] oldScroll = new int[count];
|
int[] oldScroll = new int[count];
|
||||||
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
|
||||||
|
|
||||||
int[] newScroll = new int[count];
|
int[] newScroll = new int[count];
|
||||||
|
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
||||||
getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
|
getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
|
||||||
|
|
||||||
int taskCount = getTaskViewCount();
|
int taskCount = getTaskViewCount();
|
||||||
int scrollDiffPerPage = 0;
|
int scrollDiffPerPage = 0;
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
@@ -1200,13 +1296,17 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
|
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
|
||||||
if (scrollDiff != 0) {
|
if (scrollDiff != 0) {
|
||||||
if (UNSTABLE_SPRINGS.get() && child instanceof TaskView) {
|
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,
|
addAnim(new SpringObjectAnimator<>(child, VIEW_TRANSLATE_X,
|
||||||
MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
|
MIN_VISIBLE_CHANGE_PIXELS, damping,
|
||||||
SpringForce.STIFFNESS_MEDIUM,
|
stiffness, 0, scrollDiff), duration, ACCEL, anim);
|
||||||
0, scrollDiff), duration, ACCEL, anim);
|
|
||||||
} else {
|
} else {
|
||||||
addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff), duration,
|
Property translationProperty = mOrientationHandler.getPrimaryViewTranslate();
|
||||||
ACCEL, anim);
|
addAnim(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff),
|
||||||
|
duration, ACCEL, anim);
|
||||||
}
|
}
|
||||||
|
|
||||||
needsCurveUpdates = true;
|
needsCurveUpdates = true;
|
||||||
@@ -1252,6 +1352,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
|
|
||||||
if (getTaskViewCount() == 0) {
|
if (getTaskViewCount() == 0) {
|
||||||
removeView(mClearAllButton);
|
removeView(mClearAllButton);
|
||||||
|
hideActionsView();
|
||||||
startHome();
|
startHome();
|
||||||
} else {
|
} else {
|
||||||
snapToPageImmediately(pageToSnapTo);
|
snapToPageImmediately(pageToSnapTo);
|
||||||
@@ -1396,15 +1497,17 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mClearAllButton.setContentAlpha(mContentAlpha);
|
mClearAllButton.setContentAlpha(mContentAlpha);
|
||||||
|
|
||||||
int alphaInt = Math.round(alpha * 255);
|
int alphaInt = Math.round(alpha * 255);
|
||||||
mEmptyMessagePaint.setAlpha(alphaInt);
|
mEmptyMessagePaint.setAlpha(alphaInt);
|
||||||
mEmptyIcon.setAlpha(alphaInt);
|
mEmptyIcon.setAlpha(alphaInt);
|
||||||
|
|
||||||
if (alpha > 0) {
|
if (alpha > 0) {
|
||||||
setVisibility(VISIBLE);
|
setVisibility(VISIBLE);
|
||||||
|
if (!mGestureRunning) {
|
||||||
|
showActionsView();
|
||||||
|
}
|
||||||
} else if (!mFreezeViewVisibility) {
|
} else if (!mFreezeViewVisibility) {
|
||||||
setVisibility(GONE);
|
setVisibility(GONE);
|
||||||
|
hideActionsView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1418,10 +1521,27 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
|
|
||||||
if (!mFreezeViewVisibility) {
|
if (!mFreezeViewVisibility) {
|
||||||
setVisibility(mContentAlpha > 0 ? VISIBLE : GONE);
|
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
|
@Override
|
||||||
public void onViewAdded(View child) {
|
public void onViewAdded(View child) {
|
||||||
super.onViewAdded(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.fromTaskThumbnailView(tv.getThumbnail(), this);
|
||||||
appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
|
appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
|
||||||
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
|
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
|
||||||
@@ -1799,7 +1920,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int computeMinScrollX() {
|
protected int computeMinScroll() {
|
||||||
if (getTaskViewCount() > 0) {
|
if (getTaskViewCount() > 0) {
|
||||||
if (mDisallowScrollToClearAll) {
|
if (mDisallowScrollToClearAll) {
|
||||||
// We aren't showing the clear all button,
|
// 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 getScrollForPage(mTaskViewStartIndex);
|
||||||
}
|
}
|
||||||
return super.computeMinScrollX();
|
return super.computeMinScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int computeMaxScrollX() {
|
protected int computeMaxScroll() {
|
||||||
if (getTaskViewCount() > 0) {
|
if (getTaskViewCount() > 0) {
|
||||||
if (mDisallowScrollToClearAll) {
|
if (mDisallowScrollToClearAll) {
|
||||||
// We aren't showing the clear all button,
|
// 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 getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
|
||||||
}
|
}
|
||||||
return super.computeMaxScrollX();
|
return super.computeMaxScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClearAllButton getClearAllButton() {
|
public ClearAllButton getClearAllButton() {
|
||||||
@@ -1848,31 +1969,30 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int startScroll = getScrollForPage(getRunningTaskIndex());
|
int startScroll = getScrollForPage(getRunningTaskIndex());
|
||||||
int offsetX = startScroll - getScrollX();
|
int offsetX = startScroll - mOrientationHandler.getPrimaryScroll(this);
|
||||||
offsetX *= getScaleX();
|
offsetX *= mOrientationHandler.getPrimaryScale(this);
|
||||||
return offsetX;
|
return offsetX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumer<MotionEvent> getEventDispatcher(RotationMode rotationMode) {
|
public Consumer<MotionEvent> getEventDispatcher(RotationMode navBarRotationMode) {
|
||||||
if (rotationMode.isTransposed) {
|
float degreesRotated;
|
||||||
Matrix transform = new Matrix();
|
if (navBarRotationMode == RotationMode.NORMAL) {
|
||||||
transform.setRotate(-rotationMode.surfaceRotation);
|
degreesRotated = RotationHelper.getDegreesFromRotation(mLayoutRotation);
|
||||||
|
|
||||||
if (getWidth() > 0 && getHeight() > 0) {
|
|
||||||
float scale = ((float) getWidth()) / getHeight();
|
|
||||||
transform.postScale(scale, 1 / scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix inverse = new Matrix();
|
|
||||||
transform.invert(inverse);
|
|
||||||
return e -> {
|
|
||||||
e.transform(transform);
|
|
||||||
super.onTouchEvent(e);
|
|
||||||
e.transform(inverse);
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
|
degreesRotated = -navBarRotationMode.surfaceRotation;
|
||||||
|
}
|
||||||
|
if (degreesRotated == 0) {
|
||||||
return super::onTouchEvent;
|
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() {
|
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) */
|
/** @param isEmpty Whether RecentsView is empty (i.e. has no children) */
|
||||||
void onEmptyMessageUpdated(boolean isEmpty);
|
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.graphics.Shader;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.FloatProperty;
|
import android.util.FloatProperty;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Property;
|
import android.util.Property;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package com.android.quickstep.views;
|
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 android.widget.Toast.LENGTH_SHORT;
|
||||||
|
|
||||||
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
|
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.LINEAR;
|
||||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
@@ -41,25 +46,24 @@ import android.os.Handler;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.FloatProperty;
|
import android.util.FloatProperty;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
|
import com.android.launcher3.states.RotationHelper;
|
||||||
import com.android.launcher3.testing.TestLogging;
|
import com.android.launcher3.testing.TestLogging;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
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;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
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 float mWindowCornerRadius;
|
||||||
private final BaseDraggingActivity mActivity;
|
private final BaseDraggingActivity mActivity;
|
||||||
|
|
||||||
@Nullable private View mActionsView;
|
|
||||||
|
|
||||||
private ObjectAnimator mIconAndDimAnimator;
|
private ObjectAnimator mIconAndDimAnimator;
|
||||||
private float mIconScaleAnimStartProgress = 0;
|
private float mIconScaleAnimStartProgress = 0;
|
||||||
private float mFocusTransitionProgress = 1;
|
private float mFocusTransitionProgress = 1;
|
||||||
@@ -237,18 +239,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
||||||
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
|
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
|
||||||
mSnapshotView.setLayoutParams(thumbnailParams);
|
mSnapshotView.setLayoutParams(thumbnailParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTaskOverlayModal() {
|
||||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
|
return mSnapshotView.getTaskOverlay().isOverlayModal();
|
||||||
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 TaskMenuView getMenuView() {
|
public TaskMenuView getMenuView() {
|
||||||
@@ -262,10 +256,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
/**
|
/**
|
||||||
* Updates this task view to the given {@param task}.
|
* Updates this task view to the given {@param task}.
|
||||||
*/
|
*/
|
||||||
public void bind(Task task) {
|
public void bind(Task task, int recentsRotation) {
|
||||||
cancelPendingLoadTasks();
|
cancelPendingLoadTasks();
|
||||||
mTask = task;
|
mTask = task;
|
||||||
mSnapshotView.bind(task);
|
mSnapshotView.bind(task);
|
||||||
|
setOverviewRotation(recentsRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task getTask() {
|
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) {
|
private void setIconAndDimTransitionProgress(float progress, boolean invert) {
|
||||||
if (invert) {
|
if (invert) {
|
||||||
progress = 1 - progress;
|
progress = 1 - progress;
|
||||||
@@ -449,11 +480,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
mIconView.setScaleX(scale);
|
mIconView.setScaleX(scale);
|
||||||
mIconView.setScaleY(scale);
|
mIconView.setScaleY(scale);
|
||||||
|
|
||||||
|
|
||||||
if (mActionsView != null && isRunningTask()) {
|
|
||||||
mActionsView.setAlpha(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
mFooterVerticalOffset = 1.0f - scale;
|
mFooterVerticalOffset = 1.0f - scale;
|
||||||
for (FooterWrapper footer : mFooters) {
|
for (FooterWrapper footer : mFooters) {
|
||||||
if (footer != null) {
|
if (footer != null) {
|
||||||
@@ -544,31 +570,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
mMenuView.setScaleX(getScaleX());
|
mMenuView.setScaleX(getScaleX());
|
||||||
mMenuView.setScaleY(getScaleY());
|
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.
|
* 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);
|
addView(view, indexToAdd);
|
||||||
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
|
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
|
||||||
layoutParams.gravity =
|
layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL;
|
||||||
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
|
||||||
layoutParams.bottomMargin =
|
layoutParams.bottomMargin =
|
||||||
((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin;
|
((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin;
|
||||||
view.setAlpha(mFooterAlpha);
|
view.setAlpha(mFooterAlpha);
|
||||||
@@ -851,9 +853,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
mFullscreenProgress = progress;
|
mFullscreenProgress = progress;
|
||||||
boolean isFullscreen = mFullscreenProgress > 0;
|
boolean isFullscreen = mFullscreenProgress > 0;
|
||||||
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
||||||
if (mActionsView != null) {
|
|
||||||
mActionsView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
|
||||||
}
|
|
||||||
setClipChildren(!isFullscreen);
|
setClipChildren(!isFullscreen);
|
||||||
setClipToPadding(!isFullscreen);
|
setClipToPadding(!isFullscreen);
|
||||||
|
|
||||||
@@ -934,5 +933,4 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
mScale = scale;
|
mScale = scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
android:id="@+id/icon"
|
android:id="@+id/icon"
|
||||||
android:layout_width="@dimen/task_thumbnail_icon_size"
|
android:layout_width="@dimen/task_thumbnail_icon_size"
|
||||||
android:layout_height="@dimen/task_thumbnail_icon_size"
|
android:layout_height="@dimen/task_thumbnail_icon_size"
|
||||||
android:layout_gravity="top|center_horizontal"
|
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:importantForAccessibility="no"/>
|
android:importantForAccessibility="no"/>
|
||||||
</com.android.quickstep.views.TaskView>
|
</com.android.quickstep.views.TaskView>
|
||||||
@@ -66,27 +66,32 @@
|
|||||||
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
|
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
|
||||||
<string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
|
<string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Hotseat migration notification title -->
|
<!-- 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 -->
|
<!-- 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>
|
<string translatable="false" name="hotseat_edu_prompt_content">Tap to set up</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 -->
|
<!-- Hotseat educational strings for users who don't qualify for migration -->
|
||||||
<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_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 -->
|
<!-- 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 -->
|
<!-- 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>
|
<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 -->
|
<!-- 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 -->
|
<!-- Button text to dismiss opt in for fully predicted hotseat -->
|
||||||
<string translatable="false" name="hotseat_migrate_dismiss">No thanks</string>
|
<string translatable="false" name="hotseat_edu_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>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
|
<!-- 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.LauncherState.ScaleAndTranslation;
|
||||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||||
|
import com.android.launcher3.accessibility.SystemActions;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.model.WellbeingModel;
|
import com.android.launcher3.model.WellbeingModel;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
import com.android.launcher3.proxy.ProxyActivityStarter;
|
import com.android.launcher3.proxy.ProxyActivityStarter;
|
||||||
import com.android.launcher3.proxy.StartActivityParams;
|
import com.android.launcher3.proxy.StartActivityParams;
|
||||||
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.launcher3.uioverrides.BackButtonAlphaHandler;
|
import com.android.launcher3.uioverrides.BackButtonAlphaHandler;
|
||||||
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
||||||
import com.android.launcher3.util.UiThreadHelper;
|
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.SystemUiProxy;
|
||||||
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
|
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
|
||||||
import com.android.quickstep.util.ShelfPeekAnim;
|
import com.android.quickstep.util.ShelfPeekAnim;
|
||||||
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -61,6 +64,8 @@ import java.util.stream.Stream;
|
|||||||
public abstract class BaseQuickstepLauncher extends Launcher
|
public abstract class BaseQuickstepLauncher extends Launcher
|
||||||
implements NavigationModeChangeListener {
|
implements NavigationModeChangeListener {
|
||||||
|
|
||||||
|
protected SystemActions mSystemActions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reusable command for applying the back button alpha on the background thread.
|
* Reusable command for applying the back button alpha on the background thread.
|
||||||
*/
|
*/
|
||||||
@@ -73,6 +78,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
mSystemActions = new SystemActions(this);
|
||||||
|
|
||||||
SysUINavigationMode.Mode mode = SysUINavigationMode.INSTANCE.get(this)
|
SysUINavigationMode.Mode mode = SysUINavigationMode.INSTANCE.get(this)
|
||||||
.addModeChangeListener(this);
|
.addModeChangeListener(this);
|
||||||
@@ -130,6 +136,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
getRotationHelper().setRotationHadDifferentUI(newMode != Mode.NO_BUTTON);
|
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
|
@Override
|
||||||
public void onEnterAnimationComplete() {
|
public void onEnterAnimationComplete() {
|
||||||
super.onEnterAnimationComplete();
|
super.onEnterAnimationComplete();
|
||||||
@@ -193,6 +205,15 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
// removes the task itself.
|
// removes the task itself.
|
||||||
startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
|
startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register all system actions once they are available
|
||||||
|
mSystemActions.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
mSystemActions.unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,7 +222,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
|
|
||||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
|
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
|
||||||
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
||||||
getOverviewPanelContainer().bringToFront();
|
getOverviewPanel().bringToFront();
|
||||||
|
if (getActionsView() != null) {
|
||||||
|
getActionsView().bringToFront();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,9 +241,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
@Override
|
@Override
|
||||||
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
|
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
|
||||||
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
|
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
|
||||||
float offscreenTranslationX = getDeviceProfile().widthPx
|
PagedOrientationHandler layoutVertical =
|
||||||
- getOverviewPanel().getPaddingStart();
|
((RecentsView)getOverviewPanel()).getPagedViewOrientedState().getOrientationHandler();
|
||||||
return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
|
return layoutVertical.getScaleAndTranslation(getDeviceProfile(),
|
||||||
|
getOverviewPanel());
|
||||||
}
|
}
|
||||||
return super.getOverviewScaleAndTranslationForNormalState();
|
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 {
|
implements StateHandler {
|
||||||
protected final T mRecentsView;
|
protected final T mRecentsView;
|
||||||
protected final Launcher mLauncher;
|
protected final Launcher mLauncher;
|
||||||
|
protected final View mActionsView;
|
||||||
|
|
||||||
public BaseRecentsViewStateController(@NonNull Launcher launcher) {
|
public BaseRecentsViewStateController(@NonNull Launcher launcher) {
|
||||||
mLauncher = launcher;
|
mLauncher = launcher;
|
||||||
mRecentsView = launcher.getOverviewPanel();
|
mRecentsView = launcher.getOverviewPanel();
|
||||||
|
mActionsView = launcher.getActionsView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,6 +74,10 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
|||||||
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
|
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
|
||||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||||
SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
|
SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
|
||||||
|
if (mActionsView != null) {
|
||||||
|
mActionsView.setTranslationX(translationX);
|
||||||
|
mActionsView.setAlpha(state.overviewUi ? 1f : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,6 +124,11 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
|||||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||||
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
|
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
|
||||||
builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
|
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.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
@@ -31,6 +32,7 @@ import androidx.annotation.UiThread;
|
|||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.quickstep.util.ActivityInitListener;
|
import com.android.quickstep.util.ActivityInitListener;
|
||||||
import com.android.quickstep.util.ShelfPeekAnim;
|
import com.android.quickstep.util.ShelfPeekAnim;
|
||||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
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);
|
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();
|
void onSwipeUpToRecentsComplete();
|
||||||
|
|
||||||
default void onSwipeUpToHomeComplete() { }
|
default void onSwipeUpToHomeComplete() { }
|
||||||
@@ -148,13 +159,18 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
|
|||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
static RectF getDefaultWindowTargetRect(DeviceProfile dp) {
|
static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
|
||||||
|
DeviceProfile dp) {
|
||||||
final int halfIconSize = dp.iconSizePx / 2;
|
final int halfIconSize = dp.iconSizePx / 2;
|
||||||
final float targetCenterX = dp.availableWidthPx / 2f;
|
float primaryDimension = orientationHandler
|
||||||
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
|
.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.
|
// Fallback to animate to center of screen.
|
||||||
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
|
return new RectF(targetX - halfIconSize, targetY - halfIconSize,
|
||||||
targetCenterX + halfIconSize, targetCenterY + halfIconSize);
|
targetX + halfIconSize, targetY + halfIconSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
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_FINISHED);
|
||||||
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
|
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.content.pm.ResolveInfo;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
||||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -44,18 +45,11 @@ import java.util.Objects;
|
|||||||
* and provide callers the relevant classes.
|
* and provide callers the relevant classes.
|
||||||
*/
|
*/
|
||||||
public final class OverviewComponentObserver {
|
public final class OverviewComponentObserver {
|
||||||
private final BroadcastReceiver mUserPreferenceChangeReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mUserPreferenceChangeReceiver =
|
||||||
@Override
|
new SimpleBroadcastReceiver(this::updateOverviewTargets);
|
||||||
public void onReceive(Context context, Intent intent) {
|
private final BroadcastReceiver mOtherHomeAppUpdateReceiver =
|
||||||
updateOverviewTargets();
|
new SimpleBroadcastReceiver(this::updateOverviewTargets);
|
||||||
}
|
|
||||||
};
|
|
||||||
private final BroadcastReceiver mOtherHomeAppUpdateReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
updateOverviewTargets();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final RecentsAnimationDeviceState mDeviceState;
|
private final RecentsAnimationDeviceState mDeviceState;
|
||||||
private final Intent mCurrentHomeIntent;
|
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
|
* Update overview intent and {@link BaseActivityInterface} based off the current launcher home
|
||||||
* component.
|
* component.
|
||||||
@@ -131,11 +129,8 @@ public final class OverviewComponentObserver {
|
|||||||
mOverviewIntent = mMyHomeIntent;
|
mOverviewIntent = mMyHomeIntent;
|
||||||
mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
|
mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
|
||||||
|
|
||||||
if (mUpdateRegisteredPackage != null) {
|
// Remove any update listener as we don't care about other packages.
|
||||||
// Remove any update listener as we don't care about other packages.
|
unregisterOtherHomeAppUpdateReceiver();
|
||||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
|
||||||
mUpdateRegisteredPackage = null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// The default home app is a different launcher. Use the fallback Overview instead.
|
// 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
|
// Listen for package updates of this app (and remove any previously attached
|
||||||
// package listener).
|
// package listener).
|
||||||
if (defaultHome == null) {
|
if (defaultHome == null) {
|
||||||
if (mUpdateRegisteredPackage != null) {
|
unregisterOtherHomeAppUpdateReceiver();
|
||||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
|
||||||
}
|
|
||||||
} else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
|
} else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
|
||||||
if (mUpdateRegisteredPackage != null) {
|
unregisterOtherHomeAppUpdateReceiver();
|
||||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
mUpdateRegisteredPackage = defaultHome.getPackageName();
|
mUpdateRegisteredPackage = defaultHome.getPackageName();
|
||||||
mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter(
|
mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter(
|
||||||
@@ -170,7 +161,10 @@ public final class OverviewComponentObserver {
|
|||||||
*/
|
*/
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
mContext.unregisterReceiver(mUserPreferenceChangeReceiver);
|
mContext.unregisterReceiver(mUserPreferenceChangeReceiver);
|
||||||
|
unregisterOtherHomeAppUpdateReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterOtherHomeAppUpdateReceiver() {
|
||||||
if (mUpdateRegisteredPackage != null) {
|
if (mUpdateRegisteredPackage != null) {
|
||||||
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
|
||||||
mUpdateRegisteredPackage = null;
|
mUpdateRegisteredPackage = null;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around RecentsAnimationController to help with some synchronization
|
* Wrapper around RecentsAnimationControllerCompat to help with some synchronization
|
||||||
*/
|
*/
|
||||||
public class RecentsAnimationController {
|
public class RecentsAnimationController {
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ package com.android.quickstep;
|
|||||||
|
|
||||||
import static android.content.Intent.ACTION_USER_UNLOCKED;
|
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.NO_BUTTON;
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_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.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.Surface;
|
|
||||||
|
|
||||||
import androidx.annotation.BinderThread;
|
import androidx.annotation.BinderThread;
|
||||||
|
|
||||||
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.ResourceUtils;
|
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.util.DefaultDisplay;
|
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;
|
||||||
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||||
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
||||||
|
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -80,6 +76,7 @@ public class RecentsAnimationDeviceState implements
|
|||||||
private final SysUINavigationMode mSysUiNavMode;
|
private final SysUINavigationMode mSysUiNavMode;
|
||||||
private final DefaultDisplay mDefaultDisplay;
|
private final DefaultDisplay mDefaultDisplay;
|
||||||
private final int mDisplayId;
|
private final int mDisplayId;
|
||||||
|
private int mDisplayRotation;
|
||||||
|
|
||||||
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
||||||
|
|
||||||
@@ -87,10 +84,7 @@ public class RecentsAnimationDeviceState implements
|
|||||||
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
|
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
|
||||||
private NavBarPosition mNavBarPosition;
|
private NavBarPosition mNavBarPosition;
|
||||||
|
|
||||||
private final RectF mSwipeUpTouchRegion = new RectF();
|
|
||||||
private final Region mDeferredGestureRegion = new Region();
|
private final Region mDeferredGestureRegion = new Region();
|
||||||
private final RectF mAssistantLeftRegion = new RectF();
|
|
||||||
private final RectF mAssistantRightRegion = new RectF();
|
|
||||||
private boolean mAssistantAvailable;
|
private boolean mAssistantAvailable;
|
||||||
private float mAssistantVisibility;
|
private float mAssistantVisibility;
|
||||||
|
|
||||||
@@ -106,10 +100,13 @@ public class RecentsAnimationDeviceState implements
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private OrientationTouchTransformer mOrientationTouchTransformer;
|
||||||
|
|
||||||
private Region mExclusionRegion;
|
private Region mExclusionRegion;
|
||||||
private SystemGestureExclusionListenerCompat mExclusionListener;
|
private SystemGestureExclusionListenerCompat mExclusionListener;
|
||||||
|
|
||||||
private final List<ComponentName> mGestureBlockedActivities;
|
private final List<ComponentName> mGestureBlockedActivities;
|
||||||
|
private TaskStackChangeListener mFrozenTaskListener;
|
||||||
|
|
||||||
public RecentsAnimationDeviceState(Context context) {
|
public RecentsAnimationDeviceState(Context context) {
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
@@ -139,6 +136,8 @@ public class RecentsAnimationDeviceState implements
|
|||||||
};
|
};
|
||||||
runOnDestroy(mExclusionListener::unregister);
|
runOnDestroy(mExclusionListener::unregister);
|
||||||
|
|
||||||
|
setupOrientationSwipeHandler(context);
|
||||||
|
|
||||||
// Register for navigation mode changes
|
// Register for navigation mode changes
|
||||||
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
||||||
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(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) {
|
private void runOnDestroy(Runnable action) {
|
||||||
mOnDestroyActions.add(action);
|
mOnDestroyActions.add(action);
|
||||||
}
|
}
|
||||||
@@ -198,7 +217,10 @@ public class RecentsAnimationDeviceState implements
|
|||||||
mExclusionListener.unregister();
|
mExclusionListener.unregister();
|
||||||
}
|
}
|
||||||
mMode = newMode;
|
mMode = newMode;
|
||||||
|
|
||||||
mNavBarPosition = new NavBarPosition(mMode, mDefaultDisplay.getInfo());
|
mNavBarPosition = new NavBarPosition(mMode, mDefaultDisplay.getInfo());
|
||||||
|
|
||||||
|
mOrientationTouchTransformer.setNavigationMode(mMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -207,8 +229,10 @@ public class RecentsAnimationDeviceState implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDisplayRotation = info.rotation;
|
||||||
mNavBarPosition = new NavBarPosition(mMode, info);
|
mNavBarPosition = new NavBarPosition(mMode, info);
|
||||||
updateGestureTouchRegions();
|
updateGestureTouchRegions();
|
||||||
|
mOrientationTouchTransformer.createOrAddTouchRegion(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -380,50 +404,14 @@ public class RecentsAnimationDeviceState implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Resources res = mContext.getResources();
|
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
||||||
*/
|
*/
|
||||||
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
|
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.
|
* is in the swipe up gesture region.
|
||||||
*/
|
*/
|
||||||
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
|
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) {
|
public boolean canTriggerAssistantAction(MotionEvent ev) {
|
||||||
return mAssistantAvailable
|
return mAssistantAvailable
|
||||||
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
||||||
&& (mAssistantLeftRegion.contains(ev.getX(), ev.getY())
|
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
|
||||||
|| mAssistantRightRegion.contains(ev.getX(), ev.getY()))
|
|
||||||
&& !isLockToAppActive();
|
&& !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) {
|
public void dump(PrintWriter pw) {
|
||||||
pw.println("DeviceState:");
|
pw.println("DeviceState:");
|
||||||
pw.println(" canStartSystemGesture=" + canStartSystemGesture());
|
pw.println(" canStartSystemGesture=" + canStartSystemGesture());
|
||||||
@@ -504,5 +516,8 @@ public class RecentsAnimationDeviceState implements
|
|||||||
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
||||||
pw.println(" assistantDisabled="
|
pw.println(" assistantDisabled="
|
||||||
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
|
+ 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 java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
public class LayoutUtils {
|
public class LayoutUtils {
|
||||||
|
|
||||||
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
|
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.PendingIntent;
|
||||||
import android.app.usage.UsageStatsManager;
|
import android.app.usage.UsageStatsManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
@@ -33,6 +34,9 @@ public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToast() throws Exception {
|
public void testToast() throws Exception {
|
||||||
|
// b/150303529
|
||||||
|
if (Build.MODEL.contains("Cuttlefish")) return;
|
||||||
|
|
||||||
startAppFast(CALCULATOR_PACKAGE);
|
startAppFast(CALCULATOR_PACKAGE);
|
||||||
|
|
||||||
final UsageStatsManager usageStatsManager =
|
final UsageStatsManager usageStatsManager =
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
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.OverviewTask;
|
||||||
import com.android.launcher3.tapl.TestHelpers;
|
import com.android.launcher3.tapl.TestHelpers;
|
||||||
import com.android.launcher3.ui.TaplTestsLauncher3;
|
import com.android.launcher3.ui.TaplTestsLauncher3;
|
||||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
|
||||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
|
|
||||||
@@ -254,8 +251,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
|||||||
@Test
|
@Test
|
||||||
@NavigationModeSwitch
|
@NavigationModeSwitch
|
||||||
@PortraitLandscape
|
@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 {
|
public void testQuickSwitchFromApp() throws Exception {
|
||||||
startTestActivity(2);
|
startTestActivity(2);
|
||||||
startTestActivity(3);
|
startTestActivity(3);
|
||||||
|
|||||||
@@ -44,8 +44,13 @@
|
|||||||
layout="@layout/hotseat" />
|
layout="@layout/hotseat" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/overview_panel_container"
|
android:id="@+id/overview_panel"
|
||||||
layout="@layout/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
|
<!-- Keep these behind the workspace so that they are not visible when
|
||||||
we go into AllApps -->
|
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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<FrameLayout
|
<Space
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/overview_panel_recents"
|
android:layout_width="0dp"
|
||||||
android:layout_width="0dp"
|
android:layout_height="0dp" />
|
||||||
android:layout_height="0dp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
+53
-1
@@ -121,5 +121,57 @@
|
|||||||
<bool name="config_enableTaskSnapshotPreloading">true</bool>
|
<bool name="config_enableTaskSnapshotPreloading">true</bool>
|
||||||
|
|
||||||
<!-- Configuration resources -->
|
<!-- 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>
|
</resources>
|
||||||
|
|||||||
@@ -2783,6 +2783,26 @@ public class CellLayout extends ViewGroup implements Transposable {
|
|||||||
return false;
|
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) {
|
public boolean isRegionVacant(int x, int y, int spanX, int spanY) {
|
||||||
return mOccupied.isRegionVacant(x, y, spanX, spanY);
|
return mOccupied.isRegionVacant(x, y, spanX, spanY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.animation.OvershootInterpolator;
|
import android.view.animation.OvershootInterpolator;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -274,7 +273,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
|
|
||||||
// UI and state for the overview panel
|
// UI and state for the overview panel
|
||||||
private View mOverviewPanel;
|
private View mOverviewPanel;
|
||||||
private FrameLayout mOverviewPanelContainer;
|
private View mActionsView;
|
||||||
|
|
||||||
@Thunk
|
@Thunk
|
||||||
boolean mWorkspaceLoading = true;
|
boolean mWorkspaceLoading = true;
|
||||||
@@ -834,6 +833,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mDragLayer.clearAnimatedView();
|
mDragLayer.clearAnimatedView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,8 +1162,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
|
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
|
||||||
mWorkspace = mDragLayer.findViewById(R.id.workspace);
|
mWorkspace = mDragLayer.findViewById(R.id.workspace);
|
||||||
mWorkspace.initParentViews(mDragLayer);
|
mWorkspace.initParentViews(mDragLayer);
|
||||||
mOverviewPanel = findViewById(R.id.overview_panel_recents);
|
mOverviewPanel = findViewById(R.id.overview_panel);
|
||||||
mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
|
mActionsView = findViewById(R.id.overview_actions_view);
|
||||||
mHotseat = findViewById(R.id.hotseat);
|
mHotseat = findViewById(R.id.hotseat);
|
||||||
|
|
||||||
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
@@ -1363,7 +1363,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
|
|
||||||
protected void onUiChangedWhileSleeping() { }
|
protected void onUiChangedWhileSleeping() { }
|
||||||
|
|
||||||
public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
||||||
mWorkspace.updateNotificationDots(updatedDots);
|
mWorkspace.updateNotificationDots(updatedDots);
|
||||||
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
|
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
|
||||||
}
|
}
|
||||||
@@ -1411,8 +1411,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
return (T) mOverviewPanel;
|
return (T) mOverviewPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FrameLayout getOverviewPanelContainer() {
|
public View getActionsView() {
|
||||||
return mOverviewPanelContainer;
|
return mActionsView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DropTargetBar getDropTargetBar() {
|
public DropTargetBar getDropTargetBar() {
|
||||||
@@ -2327,6 +2327,13 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
|
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
|
||||||
getModelWriter().updateItemInDatabase(item);
|
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) {
|
if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
|
||||||
@@ -2340,6 +2347,11 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||||||
item.minSpanX = appWidgetInfo.minSpanX;
|
item.minSpanX = appWidgetInfo.minSpanX;
|
||||||
item.minSpanY = appWidgetInfo.minSpanY;
|
item.minSpanY = appWidgetInfo.minSpanY;
|
||||||
view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
|
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 {
|
} else {
|
||||||
view = new PendingAppWidgetHostView(this, item, mIconCache, false);
|
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.model.WidgetsModel;
|
||||||
import com.android.launcher3.widget.DeferredAppWidgetHostView;
|
import com.android.launcher3.widget.DeferredAppWidgetHostView;
|
||||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||||
|
import com.android.launcher3.widget.PendingAppWidgetHostView;
|
||||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -53,12 +54,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
|||||||
|
|
||||||
private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
|
private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
|
||||||
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
|
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
|
||||||
|
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private int mFlags = FLAG_RESUMED;
|
private int mFlags = FLAG_RESUMED;
|
||||||
|
|
||||||
private IntConsumer mAppWidgetRemovedCallback = null;
|
private IntConsumer mAppWidgetRemovedCallback = null;
|
||||||
|
|
||||||
|
|
||||||
public LauncherAppWidgetHost(Context context) {
|
public LauncherAppWidgetHost(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -73,7 +76,13 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
|||||||
@Override
|
@Override
|
||||||
protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
|
protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
|
||||||
AppWidgetProviderInfo appWidget) {
|
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);
|
mViews.put(appWidgetId, view);
|
||||||
return 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,
|
public AppWidgetHostView createView(Context context, int appWidgetId,
|
||||||
LauncherAppWidgetProviderInfo appWidget) {
|
LauncherAppWidgetProviderInfo appWidget) {
|
||||||
if (appWidget.isCustomWidget()) {
|
if (appWidget.isCustomWidget()) {
|
||||||
@@ -238,8 +251,8 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on an appWidget is removed for a widgetId
|
* 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) {
|
public void onAppWidgetRemoved(int appWidgetId) {
|
||||||
if (mAppWidgetRemovedCallback == null) {
|
if (mAppWidgetRemovedCallback == null) {
|
||||||
|
|||||||
@@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package com.android.launcher3;
|
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.LayoutTransition;
|
||||||
import android.animation.TimeInterpolator;
|
import android.animation.TimeInterpolator;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -35,6 +30,7 @@ import android.util.Log;
|
|||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.view.Surface;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
@@ -49,13 +45,26 @@ import android.widget.ScrollView;
|
|||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
|
import com.android.launcher3.model.PagedViewOrientedState;
|
||||||
import com.android.launcher3.pageindicators.PageIndicator;
|
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.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.OverScroller;
|
||||||
import com.android.launcher3.util.Thunk;
|
import com.android.launcher3.util.Thunk;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
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
|
* An abstraction of the original Workspace which supports browsing through a
|
||||||
* sequential list of "pages"
|
* 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 String TAG = "PagedView";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
public static boolean sFlagForcedRotation = false;
|
||||||
|
|
||||||
public static final int INVALID_PAGE = -1;
|
public static final int INVALID_PAGE = -1;
|
||||||
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
|
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")
|
@ViewDebug.ExportedProperty(category = "launcher")
|
||||||
protected int mNextPage = INVALID_PAGE;
|
protected int mNextPage = INVALID_PAGE;
|
||||||
protected int mMinScrollX;
|
protected int mMaxScroll;
|
||||||
protected int mMaxScrollX;
|
protected int mMinScroll;
|
||||||
protected OverScroller mScroller;
|
protected OverScroller mScroller;
|
||||||
private Interpolator mDefaultInterpolator;
|
private Interpolator mDefaultInterpolator;
|
||||||
private VelocityTracker mVelocityTracker;
|
private VelocityTracker mVelocityTracker;
|
||||||
@@ -106,9 +117,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
private float mDownMotionX;
|
private float mDownMotionX;
|
||||||
private float mDownMotionY;
|
private float mDownMotionY;
|
||||||
private float mLastMotionX;
|
private float mDownMotionPrimary;
|
||||||
private float mLastMotionXRemainder;
|
private float mLastMotion;
|
||||||
private float mTotalMotionX;
|
private float mLastMotionRemainder;
|
||||||
|
private float mTotalMotion;
|
||||||
|
protected PagedOrientationHandler mOrientationHandler = new PortraitPagedViewHandler();
|
||||||
|
protected final PagedViewOrientedState mOrientationState = new PagedViewOrientedState();
|
||||||
|
|
||||||
protected int[] mPageScrolls;
|
protected int[] mPageScrolls;
|
||||||
private boolean mIsBeingDragged;
|
private boolean mIsBeingDragged;
|
||||||
@@ -123,11 +137,14 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
protected boolean mIsPageInTransition = false;
|
protected boolean mIsPageInTransition = false;
|
||||||
|
|
||||||
protected float mSpringOverScrollX;
|
protected float mSpringOverScroll;
|
||||||
|
|
||||||
protected boolean mWasInOverscroll = false;
|
protected boolean mWasInOverscroll = false;
|
||||||
|
|
||||||
protected int mUnboundedScrollX;
|
protected int mUnboundedScroll;
|
||||||
|
|
||||||
|
protected int mLayoutRotation = Surface.ROTATION_0;
|
||||||
|
protected int mDisplayRotation = Surface.ROTATION_0;
|
||||||
|
|
||||||
// Page Indicator
|
// Page Indicator
|
||||||
@Thunk int mPageIndicatorViewId;
|
@Thunk int mPageIndicatorViewId;
|
||||||
@@ -166,11 +183,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
* Initializes various states for this workspace.
|
* Initializes various states for this workspace.
|
||||||
*/
|
*/
|
||||||
protected void init() {
|
protected void init() {
|
||||||
mScroller = new OverScroller(getContext());
|
Context context = getContext();
|
||||||
|
mScroller = new OverScroller(context);
|
||||||
setDefaultInterpolator(Interpolators.SCROLL);
|
setDefaultInterpolator(Interpolators.SCROLL);
|
||||||
mCurrentPage = 0;
|
mCurrentPage = 0;
|
||||||
|
|
||||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||||
mTouchSlop = configuration.getScaledPagingTouchSlop();
|
mTouchSlop = configuration.getScaledPagingTouchSlop();
|
||||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||||
|
|
||||||
@@ -182,6 +200,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
if (Utilities.ATLEAST_OREO) {
|
if (Utilities.ATLEAST_OREO) {
|
||||||
setDefaultFocusHighlightEnabled(false);
|
setDefaultFocusHighlightEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sFlagForcedRotation = Utilities.isForcedRotation(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setDefaultInterpolator(Interpolator interpolator) {
|
protected void setDefaultInterpolator(Interpolator interpolator) {
|
||||||
@@ -236,12 +256,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
*/
|
*/
|
||||||
protected void updateCurrentPageScroll() {
|
protected void updateCurrentPageScroll() {
|
||||||
// If the current page is invalid, just reset the scroll position to zero
|
// If the current page is invalid, just reset the scroll position to zero
|
||||||
int newX = 0;
|
int newPosition = 0;
|
||||||
if (0 <= mCurrentPage && mCurrentPage < getPageCount()) {
|
if (0 <= mCurrentPage && mCurrentPage < getPageCount()) {
|
||||||
newX = getScrollForPage(mCurrentPage);
|
newPosition = getScrollForPage(mCurrentPage);
|
||||||
}
|
}
|
||||||
scrollTo(newX, 0);
|
mOrientationHandler.set(this, VIEW_SCROLL_TO, newPosition);
|
||||||
mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
|
mOrientationHandler.scrollerStartScroll(mScroller, newPosition);
|
||||||
forceFinishScroller(true);
|
forceFinishScroller(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +305,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
int dir = !mIsRtl ? 1 : - 1;
|
int dir = !mIsRtl ? 1 : - 1;
|
||||||
int currScroll = getScrollForPage(page);
|
int currScroll = getScrollForPage(page);
|
||||||
int prevScroll;
|
int prevScroll;
|
||||||
while (currScroll < mMinScrollX) {
|
while (currScroll < mMinScroll) {
|
||||||
page += dir;
|
page += dir;
|
||||||
prevScroll = currScroll;
|
prevScroll = currScroll;
|
||||||
currScroll = getScrollForPage(page);
|
currScroll = getScrollForPage(page);
|
||||||
@@ -294,7 +314,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (currScroll > mMaxScrollX) {
|
while (currScroll > mMaxScroll) {
|
||||||
page -= dir;
|
page -= dir;
|
||||||
prevScroll = currScroll;
|
prevScroll = currScroll;
|
||||||
currScroll = getScrollForPage(page);
|
currScroll = getScrollForPage(page);
|
||||||
@@ -378,45 +398,73 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
|
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getUnboundedScrollX() {
|
protected int getUnboundedScroll() {
|
||||||
return mUnboundedScrollX;
|
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
|
@Override
|
||||||
public void scrollBy(int x, int y) {
|
public void scrollBy(int x, int y) {
|
||||||
scrollTo(getUnboundedScrollX() + x, getScrollY() + y);
|
mOrientationHandler.delegateScrollBy(this, getUnboundedScroll(), x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrollTo(int x, int y) {
|
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 isBeforeFirstPage = mIsRtl ?
|
||||||
boolean isXAfterLastPage = mIsRtl ? (x < mMinScrollX) : (x > mMaxScrollX);
|
(primaryScroll > mMaxScroll) : (primaryScroll < mMinScroll);
|
||||||
|
boolean isAfterLastPage = mIsRtl ?
|
||||||
if (!isXBeforeFirstPage && !isXAfterLastPage) {
|
(primaryScroll < mMinScroll) : (primaryScroll > mMaxScroll);
|
||||||
mSpringOverScrollX = 0;
|
if (!isBeforeFirstPage && !isAfterLastPage) {
|
||||||
|
mSpringOverScroll = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isXBeforeFirstPage) {
|
if (isBeforeFirstPage) {
|
||||||
super.scrollTo(mIsRtl ? mMaxScrollX : mMinScrollX, y);
|
mOrientationHandler.delegateScrollTo(this,
|
||||||
|
secondaryScroll, mIsRtl ? mMaxScroll : mMinScroll);
|
||||||
if (mAllowOverScroll) {
|
if (mAllowOverScroll) {
|
||||||
mWasInOverscroll = true;
|
mWasInOverscroll = true;
|
||||||
if (mIsRtl) {
|
overScroll(primaryScroll - (mIsRtl ? mMaxScroll : mMinScroll));
|
||||||
overScroll(x - mMaxScrollX);
|
|
||||||
} else {
|
|
||||||
overScroll(x - mMinScrollX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (isXAfterLastPage) {
|
} else if (isAfterLastPage) {
|
||||||
super.scrollTo(mIsRtl ? mMinScrollX : mMaxScrollX, y);
|
mOrientationHandler.delegateScrollTo(this,
|
||||||
|
secondaryScroll, mIsRtl ? mMinScroll : mMaxScroll);
|
||||||
if (mAllowOverScroll) {
|
if (mAllowOverScroll) {
|
||||||
mWasInOverscroll = true;
|
mWasInOverscroll = true;
|
||||||
if (mIsRtl) {
|
overScroll(primaryScroll - (mIsRtl ? mMinScroll : mMaxScroll));
|
||||||
overScroll(x - mMinScrollX);
|
|
||||||
} else {
|
|
||||||
overScroll(x - mMaxScrollX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mWasInOverscroll) {
|
if (mWasInOverscroll) {
|
||||||
@@ -425,7 +473,13 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
super.scrollTo(x, y);
|
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() {
|
private void sendScrollAccessibilityEvent() {
|
||||||
@@ -436,9 +490,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
ev.setScrollable(true);
|
ev.setScrollable(true);
|
||||||
ev.setScrollX(getScrollX());
|
ev.setScrollX(getScrollX());
|
||||||
ev.setScrollY(getScrollY());
|
ev.setScrollY(getScrollY());
|
||||||
ev.setMaxScrollX(mMaxScrollX);
|
mOrientationHandler.setMaxScroll(ev, mMaxScroll);
|
||||||
ev.setMaxScrollY(0);
|
|
||||||
|
|
||||||
sendAccessibilityEventUnchecked(ev);
|
sendAccessibilityEventUnchecked(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,9 +511,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
protected boolean computeScrollHelper(boolean shouldInvalidate) {
|
protected boolean computeScrollHelper(boolean shouldInvalidate) {
|
||||||
if (mScroller.computeScrollOffset()) {
|
if (mScroller.computeScrollOffset()) {
|
||||||
// Don't bother scrolling if the page does not need to be moved
|
// Don't bother scrolling if the page does not need to be moved
|
||||||
if (getUnboundedScrollX() != mScroller.getCurrPos()
|
int currentScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||||
|| getScrollX() != mScroller.getCurrPos()) {
|
if (mUnboundedScroll != mScroller.getCurrPos()
|
||||||
scrollTo(mScroller.getCurrPos(), 0);
|
|| currentScroll != mScroller.getCurrPos()) {
|
||||||
|
mOrientationHandler.set(this, VIEW_SCROLL_TO, mScroller.getCurrPos());
|
||||||
}
|
}
|
||||||
if (shouldInvalidate) {
|
if (shouldInvalidate) {
|
||||||
invalidate();
|
invalidate();
|
||||||
@@ -580,7 +633,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
|
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;
|
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
|
* Initializes {@code outPageScrolls} with scroll positions for view at that index. The length
|
||||||
* of {@code outPageScrolls} should be same as the the childCount
|
* of {@code outPageScrolls} should be same as the the childCount
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
|
protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
|
||||||
ComputePageScrollsLogic scrollLogic) {
|
ComputePageScrollsLogic scrollLogic) {
|
||||||
@@ -631,36 +684,30 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
final int endIndex = mIsRtl ? -1 : childCount;
|
final int endIndex = mIsRtl ? -1 : childCount;
|
||||||
final int delta = mIsRtl ? -1 : 1;
|
final int delta = mIsRtl ? -1 : 1;
|
||||||
|
|
||||||
final int verticalCenter = (getPaddingTop() + getMeasuredHeight() + mInsets.top
|
final int pageCenter = mOrientationHandler.getCenterForPage(this, mInsets);
|
||||||
- mInsets.bottom - getPaddingBottom()) / 2;
|
|
||||||
|
|
||||||
final int scrollOffsetLeft = mInsets.left + getPaddingLeft();
|
final int scrollOffsetStart = mOrientationHandler.getScrollOffsetStart(this, mInsets);
|
||||||
final int scrollOffsetRight = getWidth() - getPaddingRight() - mInsets.right;
|
final int scrollOffsetEnd = mOrientationHandler.getScrollOffsetEnd(this, mInsets);
|
||||||
boolean pageScrollChanged = false;
|
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);
|
final View child = getPageAt(i);
|
||||||
if (scrollLogic.shouldIncludeView(child)) {
|
if (scrollLogic.shouldIncludeView(child)) {
|
||||||
final int childWidth = child.getMeasuredWidth();
|
ChildBounds bounds = mOrientationHandler.getChildBounds(child, childStart,
|
||||||
final int childRight = childLeft + childWidth;
|
pageCenter, layoutChildren);
|
||||||
|
final int primaryDimension = bounds.primaryDimension;
|
||||||
if (layoutChildren) {
|
final int childPrimaryEnd = bounds.childPrimaryEnd;
|
||||||
final int childHeight = child.getMeasuredHeight();
|
|
||||||
final int childTop = verticalCenter - childHeight / 2;
|
|
||||||
child.layout(childLeft, childTop, childRight, childTop + childHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case the pages are of different width, align the page to left or right edge
|
// In case the pages are of different width, align the page to left or right edge
|
||||||
// based on the orientation.
|
// based on the orientation.
|
||||||
final int pageScroll = mIsRtl
|
final int pageScroll = mIsRtl
|
||||||
? (childLeft - scrollOffsetLeft)
|
? (childStart - scrollOffsetStart)
|
||||||
: Math.max(0, childRight - scrollOffsetRight);
|
: Math.max(0, childPrimaryEnd - scrollOffsetEnd);
|
||||||
if (outPageScrolls[i] != pageScroll) {
|
if (outPageScrolls[i] != pageScroll) {
|
||||||
pageScrollChanged = true;
|
pageScrollChanged = true;
|
||||||
outPageScrolls[i] = pageScroll;
|
outPageScrolls[i] = pageScroll;
|
||||||
}
|
}
|
||||||
|
childStart += primaryDimension + mPageSpacing + getChildGap();
|
||||||
childLeft += childWidth + mPageSpacing + getChildGap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pageScrollChanged;
|
return pageScrollChanged;
|
||||||
@@ -671,15 +718,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateMinAndMaxScrollX() {
|
protected void updateMinAndMaxScrollX() {
|
||||||
mMinScrollX = computeMinScrollX();
|
mMinScroll = computeMinScroll();
|
||||||
mMaxScrollX = computeMaxScrollX();
|
mMaxScroll = computeMaxScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int computeMinScrollX() {
|
protected int computeMinScroll() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int computeMaxScrollX() {
|
protected int computeMaxScroll() {
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
if (childCount > 0) {
|
if (childCount > 0) {
|
||||||
final int index = mIsRtl ? 0 : childCount - 1;
|
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) {
|
protected int getChildOffset(int index) {
|
||||||
if (index < 0 || index > getChildCount() - 1) return 0;
|
if (index < 0 || index > getChildCount() - 1) return 0;
|
||||||
return getPageAt(index).getLeft();
|
View pageAtIndex = getPageAt(index);
|
||||||
|
return mOrientationHandler.getChildStart(pageAtIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -873,13 +921,13 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
case MotionEvent.ACTION_MOVE: {
|
case MotionEvent.ACTION_MOVE: {
|
||||||
/*
|
/*
|
||||||
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
|
* 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) {
|
if (mActivePointerId != INVALID_POINTER) {
|
||||||
determineScrollingStart(ev);
|
determineScrollingStart(ev);
|
||||||
}
|
}
|
||||||
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
|
// 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)
|
// i.e. fall through to the next case (don't break)
|
||||||
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
|
// (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)
|
// 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
|
// Remember location of down touch
|
||||||
mDownMotionX = x;
|
mDownMotionX = x;
|
||||||
mDownMotionY = y;
|
mDownMotionY = y;
|
||||||
mLastMotionX = x;
|
mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
|
||||||
mLastMotionXRemainder = 0;
|
mLastMotionRemainder = 0;
|
||||||
mTotalMotionX = 0;
|
mTotalMotion = 0;
|
||||||
mActivePointerId = ev.getPointerId(0);
|
mActivePointerId = ev.getPointerId(0);
|
||||||
|
|
||||||
updateIsBeingDraggedOnTouchDown();
|
updateIsBeingDraggedOnTouchDown();
|
||||||
@@ -956,17 +1004,17 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||||
if (pointerIndex == -1) return;
|
if (pointerIndex == -1) return;
|
||||||
|
|
||||||
final float x = ev.getX(pointerIndex);
|
final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
|
||||||
final int xDiff = (int) Math.abs(x - mLastMotionX);
|
final int diff = (int) Math.abs(primaryDirection - mLastMotion);
|
||||||
final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
|
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
|
// Scroll if the user moved far enough along the X axis
|
||||||
mIsBeingDragged = true;
|
mIsBeingDragged = true;
|
||||||
mTotalMotionX += Math.abs(mLastMotionX - x);
|
mTotalMotion += Math.abs(mLastMotion - primaryDirection);
|
||||||
mLastMotionX = x;
|
mLastMotion = primaryDirection;
|
||||||
mLastMotionXRemainder = 0;
|
mLastMotionRemainder = 0;
|
||||||
onScrollInteractionBegin();
|
onScrollInteractionBegin();
|
||||||
pageBeginTransition();
|
pageBeginTransition();
|
||||||
// Stop listening for things like pinches.
|
// Stop listening for things like pinches.
|
||||||
@@ -1033,10 +1081,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
if (mScroller.isSpringing() && mSpringOverScrollX != 0) {
|
if (mScroller.isSpringing() && mSpringOverScroll != 0) {
|
||||||
int saveCount = canvas.save();
|
int saveCount = canvas.save();
|
||||||
|
mOrientationHandler.set(canvas, CANVAS_TRANSLATE, -mSpringOverScroll);
|
||||||
canvas.translate(-mSpringOverScrollX, 0);
|
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
|
|
||||||
canvas.restoreToCount(saveCount);
|
canvas.restoreToCount(saveCount);
|
||||||
@@ -1046,25 +1093,27 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void dampedOverScroll(int amount) {
|
protected void dampedOverScroll(int amount) {
|
||||||
mSpringOverScrollX = amount;
|
mSpringOverScroll = amount;
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
|
int size = mOrientationHandler.getMeasuredSize(this);
|
||||||
mSpringOverScrollX = overScrollAmount;
|
int overScrollAmount = OverScroll.dampedScroll(amount, size);
|
||||||
|
mSpringOverScroll = overScrollAmount;
|
||||||
if (mScroller.isSpringing()) {
|
if (mScroller.isSpringing()) {
|
||||||
invalidate();
|
invalidate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = Utilities.boundToRange(getScrollX(), mMinScrollX, mMaxScrollX);
|
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||||
super.scrollTo(x + overScrollAmount, getScrollY());
|
int boundedScroll = Utilities.boundToRange(primaryScroll, mMinScroll, mMaxScroll);
|
||||||
|
mOrientationHandler.delegateScrollTo(this, boundedScroll + overScrollAmount);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void overScroll(int amount) {
|
protected void overScroll(int amount) {
|
||||||
mSpringOverScrollX = amount;
|
mSpringOverScroll = amount;
|
||||||
if (mScroller.isSpringing()) {
|
if (mScroller.isSpringing()) {
|
||||||
invalidate();
|
invalidate();
|
||||||
return;
|
return;
|
||||||
@@ -1073,11 +1122,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
if (amount == 0) return;
|
if (amount == 0) return;
|
||||||
|
|
||||||
if (mFreeScroll && !mScroller.isFinished()) {
|
if (mFreeScroll && !mScroller.isFinished()) {
|
||||||
if (amount < 0) {
|
int scrollAmount = amount < 0 ? mMinScroll + amount : mMaxScroll + amount;
|
||||||
super.scrollTo(mMinScrollX + amount, getScrollY());
|
mOrientationHandler.delegateScrollTo(this, scrollAmount);
|
||||||
} else {
|
|
||||||
super.scrollTo(mMaxScrollX + amount, getScrollY());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dampedOverScroll(amount);
|
dampedOverScroll(amount);
|
||||||
}
|
}
|
||||||
@@ -1127,37 +1173,37 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remember where the motion event started
|
// Remember where the motion event started
|
||||||
mDownMotionX = mLastMotionX = ev.getX();
|
mDownMotionX = ev.getX();
|
||||||
mDownMotionY = ev.getY();
|
mDownMotionY = ev.getY();
|
||||||
mLastMotionXRemainder = 0;
|
mDownMotionPrimary = mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
|
||||||
mTotalMotionX = 0;
|
mLastMotionRemainder = 0;
|
||||||
|
mTotalMotion = 0;
|
||||||
mActivePointerId = ev.getPointerId(0);
|
mActivePointerId = ev.getPointerId(0);
|
||||||
|
|
||||||
if (mIsBeingDragged) {
|
if (mIsBeingDragged) {
|
||||||
onScrollInteractionBegin();
|
onScrollInteractionBegin();
|
||||||
pageBeginTransition();
|
pageBeginTransition();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
if (mIsBeingDragged) {
|
if (mIsBeingDragged) {
|
||||||
// Scroll to follow the motion event
|
// Scroll to follow the motion event
|
||||||
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||||
|
|
||||||
if (pointerIndex == -1) return true;
|
if (pointerIndex == -1) return true;
|
||||||
|
|
||||||
final float x = ev.getX(pointerIndex);
|
float direction = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
|
||||||
final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
|
float delta = mLastMotion + mLastMotionRemainder - direction;
|
||||||
|
mTotalMotion += Math.abs(delta);
|
||||||
mTotalMotionX += Math.abs(deltaX);
|
|
||||||
|
|
||||||
// Only scroll and update mLastMotionX if we have moved some discrete amount. We
|
// 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
|
// keep the remainder because we are actually testing if we've moved from the last
|
||||||
// scrolled position (which is discrete).
|
// scrolled position (which is discrete).
|
||||||
if (Math.abs(deltaX) >= 1.0f) {
|
if (Math.abs(delta) >= 1.0f) {
|
||||||
scrollBy((int) deltaX, 0);
|
mLastMotion = direction;
|
||||||
mLastMotionX = x;
|
mLastMotionRemainder = delta - (int) delta;
|
||||||
mLastMotionXRemainder = deltaX - (int) deltaX;
|
|
||||||
|
mOrientationHandler.set(this, VIEW_SCROLL_BY, (int) delta);
|
||||||
} else {
|
} else {
|
||||||
awakenScrollBars();
|
awakenScrollBars();
|
||||||
}
|
}
|
||||||
@@ -1170,27 +1216,31 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
if (mIsBeingDragged) {
|
if (mIsBeingDragged) {
|
||||||
final int activePointerId = mActivePointerId;
|
final int activePointerId = mActivePointerId;
|
||||||
final int pointerIndex = ev.findPointerIndex(activePointerId);
|
final int pointerIndex = ev.findPointerIndex(activePointerId);
|
||||||
final float x = ev.getX(pointerIndex);
|
final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev,
|
||||||
|
pointerIndex);
|
||||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
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);
|
int velocity = (int) mOrientationHandler.getPrimaryVelocity(velocityTracker,
|
||||||
boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
|
mActivePointerId);
|
||||||
boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
|
int delta = (int) (primaryDirection - mDownMotionPrimary);
|
||||||
boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
|
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) {
|
if (!mFreeScroll) {
|
||||||
// In the case that the page is moved far to one direction and then is flung
|
// 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
|
// 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.
|
// just return to the starting page, or if we should skip one further.
|
||||||
boolean returnToOriginalPage = false;
|
boolean returnToOriginalPage = false;
|
||||||
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
|
if (Math.abs(delta) > pageOrientedSize * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
|
||||||
Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
|
Math.signum(velocity) != Math.signum(delta) && isFling) {
|
||||||
returnToOriginalPage = true;
|
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
|
// 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.
|
// move to the left and fling to the right will register as a fling to the right.
|
||||||
|
|
||||||
if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
|
if (((isSignificantMove && !isDeltaLeft && !isFling) ||
|
||||||
(isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
|
(isFling && !isVelocityLeft)) && mCurrentPage > 0) {
|
||||||
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
|
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
|
||||||
snapToPageWithVelocity(finalPage, velocityX);
|
snapToPageWithVelocity(finalPage, velocity);
|
||||||
} else if (((isSignificantMove && isDeltaXLeft && !isFling) ||
|
} else if (((isSignificantMove && isDeltaLeft && !isFling) ||
|
||||||
(isFling && isVelocityXLeft)) &&
|
(isFling && isVelocityLeft)) &&
|
||||||
mCurrentPage < getChildCount() - 1) {
|
mCurrentPage < getChildCount() - 1) {
|
||||||
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
|
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
|
||||||
snapToPageWithVelocity(finalPage, velocityX);
|
snapToPageWithVelocity(finalPage, velocity);
|
||||||
} else {
|
} else {
|
||||||
snapToDestination();
|
snapToDestination();
|
||||||
}
|
}
|
||||||
@@ -1216,38 +1266,40 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
abortScrollerAnimation(true);
|
abortScrollerAnimation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int initialScrollX = getScrollX();
|
int initialScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||||
|
int maxScroll = mMaxScroll;
|
||||||
|
int minScroll = mMinScroll;
|
||||||
|
|
||||||
if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
|
if (((initialScroll >= maxScroll) && (isVelocityLeft || !isFling)) ||
|
||||||
((initialScrollX <= mMinScrollX) && (!isVelocityXLeft || !isFling))) {
|
((initialScroll <= minScroll) && (!isVelocityLeft || !isFling))) {
|
||||||
mScroller.springBack(getScrollX(), mMinScrollX, mMaxScrollX);
|
mScroller.springBack(initialScroll, minScroll, maxScroll);
|
||||||
mNextPage = getPageNearestToCenterOfScreen();
|
mNextPage = getPageNearestToCenterOfScreen();
|
||||||
} else {
|
} else {
|
||||||
mScroller.setInterpolator(mDefaultInterpolator);
|
mScroller.setInterpolator(mDefaultInterpolator);
|
||||||
mScroller.fling(initialScrollX, -velocityX,
|
mScroller.fling(initialScroll, -velocity,
|
||||||
mMinScrollX, mMaxScrollX,
|
minScroll, maxScroll,
|
||||||
Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
|
Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
|
||||||
|
|
||||||
int finalX = mScroller.getFinalPos();
|
int finalPos = mScroller.getFinalPos();
|
||||||
mNextPage = getPageNearestToCenterOfScreen(finalX);
|
mNextPage = getPageNearestToCenterOfScreen(finalPos);
|
||||||
|
|
||||||
int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
|
int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
|
||||||
int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
|
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
|
// 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.
|
// 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
|
// If flinging past one of the ends, don't change the velocity as it
|
||||||
// will get stopped at the end anyway.
|
// will get stopped at the end anyway.
|
||||||
int pageSnappedX = finalX < (firstPageScroll + mMinScrollX) / 2
|
int pageSnapped = finalPos < (firstPageScroll + minScroll) / 2
|
||||||
? mMinScrollX
|
? minScroll
|
||||||
: finalX > (lastPageScroll + mMaxScrollX) / 2
|
: finalPos > (lastPageScroll + maxScroll) / 2
|
||||||
? mMaxScrollX
|
? maxScroll
|
||||||
: getScrollForPage(mNextPage);
|
: getScrollForPage(mNextPage);
|
||||||
|
|
||||||
mScroller.setFinalPos(pageSnappedX);
|
mScroller.setFinalPos(pageSnapped);
|
||||||
// Ensure the scroll/snap doesn't happen too fast;
|
// Ensure the scroll/snap doesn't happen too fast;
|
||||||
int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
|
int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
|
||||||
- mScroller.getDuration();
|
- mScroller.getDuration();
|
||||||
if (extraScrollDuration > 0) {
|
if (extraScrollDuration > 0) {
|
||||||
mScroller.extendDuration(extraScrollDuration);
|
mScroller.extendDuration(extraScrollDuration);
|
||||||
}
|
}
|
||||||
@@ -1279,8 +1331,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean shouldFlingForVelocity(int velocityX) {
|
protected boolean shouldFlingForVelocity(int velocity) {
|
||||||
return Math.abs(velocityX) > mFlingThresholdVelocity;
|
return Math.abs(velocity) > mFlingThresholdVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetTouchState() {
|
private void resetTouchState() {
|
||||||
@@ -1364,8 +1416,9 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
// active pointer and adjust accordingly.
|
// active pointer and adjust accordingly.
|
||||||
// TODO: Make this decision more intelligent.
|
// TODO: Make this decision more intelligent.
|
||||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||||
mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
|
mLastMotion = mDownMotionPrimary = mOrientationHandler.getPrimaryDirection(ev,
|
||||||
mLastMotionXRemainder = 0;
|
newPointerIndex);
|
||||||
|
mLastMotionRemainder = 0;
|
||||||
mActivePointerId = ev.getPointerId(newPointerIndex);
|
mActivePointerId = ev.getPointerId(newPointerIndex);
|
||||||
if (mVelocityTracker != null) {
|
if (mVelocityTracker != null) {
|
||||||
mVelocityTracker.clear();
|
mVelocityTracker.clear();
|
||||||
@@ -1383,19 +1436,20 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getPageNearestToCenterOfScreen() {
|
public int getPageNearestToCenterOfScreen() {
|
||||||
return getPageNearestToCenterOfScreen(getScrollX());
|
return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPageNearestToCenterOfScreen(int scaledScrollX) {
|
private int getPageNearestToCenterOfScreen(int scaledScroll) {
|
||||||
int screenCenter = scaledScrollX + (getMeasuredWidth() / 2);
|
int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
|
||||||
|
int screenCenter = scaledScroll + (pageOrientationSize / 2);
|
||||||
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
|
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
|
||||||
int minDistanceFromScreenCenterIndex = -1;
|
int minDistanceFromScreenCenterIndex = -1;
|
||||||
final int childCount = getChildCount();
|
final int childCount = getChildCount();
|
||||||
for (int i = 0; i < childCount; ++i) {
|
for (int i = 0; i < childCount; ++i) {
|
||||||
View layout = getPageAt(i);
|
View layout = getPageAt(i);
|
||||||
int childWidth = layout.getMeasuredWidth();
|
int childSize = mOrientationHandler.getMeasuredSize(layout);
|
||||||
int halfChildWidth = (childWidth / 2);
|
int halfChildSize = (childSize / 2);
|
||||||
int childCenter = getChildOffset(i) + halfChildWidth;
|
int childCenter = getChildOffset(i) + halfChildSize;
|
||||||
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
|
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
|
||||||
if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
|
if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
|
||||||
minDistanceFromScreenCenter = distanceFromScreenCenter;
|
minDistanceFromScreenCenter = distanceFromScreenCenter;
|
||||||
@@ -1410,7 +1464,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isInOverScroll() {
|
protected boolean isInOverScroll() {
|
||||||
return (getScrollX() > mMaxScrollX || getScrollX() < mMinScrollX);
|
int scroll = mOrientationHandler.getPrimaryScroll(this);
|
||||||
|
return scroll > mMaxScroll || scroll < mMinScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getPageSnapDuration() {
|
protected int getPageSnapDuration() {
|
||||||
@@ -1432,10 +1487,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
protected boolean snapToPageWithVelocity(int whichPage, int velocity) {
|
protected boolean snapToPageWithVelocity(int whichPage, int velocity) {
|
||||||
whichPage = validateNewPage(whichPage);
|
whichPage = validateNewPage(whichPage);
|
||||||
int halfScreenSize = getMeasuredWidth() / 2;
|
int halfScreenSize = mOrientationHandler.getMeasuredSize(this) / 2;
|
||||||
|
|
||||||
final int newX = getScrollForPage(whichPage);
|
final int newLoc = getScrollForPage(whichPage);
|
||||||
int delta = newX - getUnboundedScrollX();
|
int delta = newLoc - getUnboundedScroll();
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
|
|
||||||
if (Math.abs(velocity) < mMinFlingVelocity) {
|
if (Math.abs(velocity) < mMinFlingVelocity) {
|
||||||
@@ -1462,7 +1517,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
|
|
||||||
if (QUICKSTEP_SPRINGS.get()) {
|
if (QUICKSTEP_SPRINGS.get()) {
|
||||||
return snapToPage(whichPage, delta, duration, false, null,
|
return snapToPage(whichPage, delta, duration, false, null,
|
||||||
velocity * Math.signum(newX - getUnboundedScrollX()), true);
|
velocity * Math.signum(delta), true);
|
||||||
} else {
|
} else {
|
||||||
return snapToPage(whichPage, delta, duration);
|
return snapToPage(whichPage, delta, duration);
|
||||||
}
|
}
|
||||||
@@ -1488,8 +1543,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||||||
TimeInterpolator interpolator) {
|
TimeInterpolator interpolator) {
|
||||||
whichPage = validateNewPage(whichPage);
|
whichPage = validateNewPage(whichPage);
|
||||||
|
|
||||||
int newX = getScrollForPage(whichPage);
|
int newLoc = getScrollForPage(whichPage);
|
||||||
final int delta = newX - getUnboundedScrollX();
|
final int delta = newLoc - getUnboundedScroll();
|
||||||
return snapToPage(whichPage, delta, duration, immediate, interpolator, 0, false);
|
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()) {
|
if (spring && QUICKSTEP_SPRINGS.get()) {
|
||||||
mScroller.startScrollSpring(getUnboundedScrollX(), delta, duration, velocity);
|
mScroller.startScrollSpring(getUnboundedScroll(), delta, duration, velocity);
|
||||||
} else {
|
} else {
|
||||||
mScroller.startScroll(getUnboundedScrollX(), delta, duration);
|
mScroller.startScroll(getUnboundedScroll(), delta, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePageIndicator();
|
updatePageIndicator();
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ import android.util.DisplayMetrics;
|
|||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
|
||||||
public class ResourceUtils {
|
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_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
|
||||||
public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
|
public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
|
||||||
|
|
||||||
|
|
||||||
public static int getNavbarSize(String resName, Resources res) {
|
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) {
|
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);
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
mCacheExpireAlarm = new Alarm();
|
mCacheExpireAlarm = new Alarm();
|
||||||
mCacheExpireAlarm.setOnAlarmListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,6 +74,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
if (mHadPendingAlarm) {
|
if (mHadPendingAlarm) {
|
||||||
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
||||||
|
mCacheExpireAlarm.setOnAlarmListener(this);
|
||||||
mHadPendingAlarm = false;
|
mHadPendingAlarm = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
|||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
if (mCacheExpireAlarm.alarmPending()) {
|
if (mCacheExpireAlarm.alarmPending()) {
|
||||||
mCacheExpireAlarm.cancelAlarm();
|
mCacheExpireAlarm.cancelAlarm();
|
||||||
|
mCacheExpireAlarm.setOnAlarmListener(null);
|
||||||
mHadPendingAlarm = true;
|
mHadPendingAlarm = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,6 +169,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
|||||||
}
|
}
|
||||||
// Cancel any pending alarm and set cache expiry after some time
|
// Cancel any pending alarm and set cache expiry after some time
|
||||||
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
|
||||||
|
mCacheExpireAlarm.setOnAlarmListener(this);
|
||||||
if (uninstallDisabled) {
|
if (uninstallDisabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.launcher3;
|
package com.android.launcher3;
|
||||||
|
|
||||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
|
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.animation.ValueAnimator;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
@@ -127,6 +128,11 @@ public final class Utilities {
|
|||||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
|
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.
|
// 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_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
|
||||||
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
|
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() {
|
private boolean isScrollingOverlay() {
|
||||||
return mLauncherOverlay != null &&
|
return mLauncherOverlay != null &&
|
||||||
((mIsRtl && getUnboundedScrollX() > mMaxScrollX)
|
((mIsRtl && getUnboundedScroll() > mMaxScroll)
|
||||||
|| (!mIsRtl && getUnboundedScrollX() < mMinScrollX));
|
|| (!mIsRtl && getUnboundedScroll() < mMinScroll));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1003,7 +1003,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
|
|
||||||
public void showPageIndicatorAtCurrentScroll() {
|
public void showPageIndicatorAtCurrentScroll() {
|
||||||
if (mPageIndicator != null) {
|
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;
|
protected boolean mUsingTabs;
|
||||||
private boolean mSearchModeWhileUsingTabs = false;
|
private boolean mSearchModeWhileUsingTabs = false;
|
||||||
|
|
||||||
private RecyclerViewFastScroller mTouchHandler;
|
protected RecyclerViewFastScroller mTouchHandler;
|
||||||
private final Point mFastScrollerOffset = new Point();
|
protected final Point mFastScrollerOffset = new Point();
|
||||||
|
|
||||||
private final MultiValueAlpha mMultiValueAlpha;
|
private final MultiValueAlpha mMultiValueAlpha;
|
||||||
|
|
||||||
@@ -238,6 +238,16 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
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) {
|
if (mTouchHandler != null) {
|
||||||
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
|
|||||||
@Override
|
@Override
|
||||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||||
super.onScrollChanged(l, t, oldl, oldt);
|
super.onScrollChanged(l, t, oldl, oldt);
|
||||||
mPageIndicator.setScroll(l, mMaxScrollX);
|
mPageIndicator.setScroll(l, mMaxScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
|||||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||||
import com.android.launcher3.anim.PropertySetter;
|
import com.android.launcher3.anim.PropertySetter;
|
||||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||||
|
import com.android.launcher3.util.DynamicResource;
|
||||||
import com.android.launcher3.util.Themes;
|
import com.android.launcher3.util.Themes;
|
||||||
import com.android.launcher3.views.ScrimView;
|
import com.android.launcher3.views.ScrimView;
|
||||||
|
import com.android.systemui.plugins.ResourceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles AllApps view transition.
|
* Handles AllApps view transition.
|
||||||
@@ -47,9 +49,6 @@ import com.android.launcher3.views.ScrimView;
|
|||||||
*/
|
*/
|
||||||
public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
|
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 =
|
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
|
||||||
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
|
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
|
||||||
|
|
||||||
@@ -187,8 +186,12 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
|
|||||||
|
|
||||||
public Animator createSpringAnimation(float... progressValues) {
|
public Animator createSpringAnimation(float... progressValues) {
|
||||||
if (UNSTABLE_SPRINGS.get()) {
|
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,
|
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);
|
return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
|||||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
// The AllAppsContainerView houses the QSB and is hence visible from the Workspace
|
// The AllAppsContainerView houses the QSB and is hence visible from the Workspace
|
||||||
// Overview states. We shouldn't intercept for the scrubber in these cases.
|
// 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);
|
return super.onInterceptTouchEvent(ev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,32 +15,40 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.anim;
|
package com.android.launcher3.anim;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
||||||
import androidx.dynamicanimation.animation.FlingAnimation;
|
import androidx.dynamicanimation.animation.FlingAnimation;
|
||||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||||
import androidx.dynamicanimation.animation.SpringForce;
|
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
|
* 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.
|
* the fling until we pass the target, then apply a spring force to pull towards the target.
|
||||||
*/
|
*/
|
||||||
public class FlingSpringAnim {
|
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 final FlingAnimation mFlingAnim;
|
||||||
private SpringAnimation mSpringAnim;
|
private SpringAnimation mSpringAnim;
|
||||||
|
|
||||||
private float mTargetPosition;
|
private float mTargetPosition;
|
||||||
|
|
||||||
public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
|
public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
|
||||||
float targetPosition, float startVelocity, float minVisChange, float minValue,
|
float startPosition, float targetPosition, float startVelocity, float minVisChange,
|
||||||
float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
|
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)
|
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
|
// Have the spring pull towards the target if we've slowed down too much before
|
||||||
// reaching it.
|
// reaching it.
|
||||||
.setMinimumVisibleChange(minVisChange)
|
.setMinimumVisibleChange(minVisChange)
|
||||||
@@ -54,8 +62,8 @@ public class FlingSpringAnim {
|
|||||||
.setStartValue(value)
|
.setStartValue(value)
|
||||||
.setStartVelocity(velocity * springVelocityFactor)
|
.setStartVelocity(velocity * springVelocityFactor)
|
||||||
.setSpring(new SpringForce(mTargetPosition)
|
.setSpring(new SpringForce(mTargetPosition)
|
||||||
.setStiffness(SPRING_STIFFNESS)
|
.setStiffness(stiffness)
|
||||||
.setDampingRatio(SPRING_DAMPING));
|
.setDampingRatio(damping));
|
||||||
mSpringAnim.addEndListener(onEndListener);
|
mSpringAnim.addEndListener(onEndListener);
|
||||||
mSpringAnim.animateToFinalPosition(mTargetPosition);
|
mSpringAnim.animateToFinalPosition(mTargetPosition);
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -101,11 +101,15 @@ public final class FeatureFlags {
|
|||||||
"Adds localized title and keyword search and ranking");
|
"Adds localized title and keyword search and ranking");
|
||||||
|
|
||||||
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
|
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(
|
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
|
||||||
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
|
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
|
||||||
|
|
||||||
|
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(
|
public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(
|
||||||
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
|
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
|
||||||
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
|
"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(
|
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
|
||||||
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
|
"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(
|
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
|
||||||
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
|
"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");
|
"MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm");
|
||||||
|
|
||||||
public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
|
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");
|
"Show launcher preview in grid picker");
|
||||||
|
|
||||||
public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
|
public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
|
||||||
@@ -139,6 +147,11 @@ public final class FeatureFlags {
|
|||||||
"ENABLE_LSQ_VELOCITY_PROVIDER", false,
|
"ENABLE_LSQ_VELOCITY_PROVIDER", false,
|
||||||
"Use Least Square algorithm for motion pause detection.");
|
"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) {
|
public static void initialize(Context context) {
|
||||||
synchronized (sDebugFlags) {
|
synchronized (sDebugFlags) {
|
||||||
for (DebugFlag flag : 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.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||||
import static com.android.launcher3.LauncherState.NORMAL;
|
import static com.android.launcher3.LauncherState.NORMAL;
|
||||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
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_CUSTOM;
|
||||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY;
|
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;
|
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) {
|
private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
|
||||||
|
if (ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS.get()) return true;
|
||||||
|
|
||||||
int folderCount = 0;
|
int folderCount = 0;
|
||||||
final ShortcutAndWidgetContainer container = currentCellLayout.getShortcutsAndWidgets();
|
final ShortcutAndWidgetContainer container = currentCellLayout.getShortcutsAndWidgets();
|
||||||
for (int i = container.getChildCount() - 1; i >= 0; --i) {
|
for (int i = container.getChildCount() - 1; i >= 0; --i) {
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||||||
@Override
|
@Override
|
||||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||||
super.onScrollChanged(l, t, oldl, 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.model.WidgetsModel;
|
||||||
import com.android.launcher3.pm.InstallSessionHelper;
|
import com.android.launcher3.pm.InstallSessionHelper;
|
||||||
import com.android.launcher3.pm.UserCache;
|
import com.android.launcher3.pm.UserCache;
|
||||||
|
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||||
import com.android.launcher3.views.ActivityContext;
|
import com.android.launcher3.views.ActivityContext;
|
||||||
import com.android.launcher3.views.BaseDragLayer;
|
import com.android.launcher3.views.BaseDragLayer;
|
||||||
|
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -128,7 +130,8 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
|
|
||||||
private static final Set<MainThreadInitializedObject> WHITELIST = new HashSet<>(
|
private static final Set<MainThreadInitializedObject> WHITELIST = new HashSet<>(
|
||||||
Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
||||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE));
|
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
||||||
|
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE));
|
||||||
|
|
||||||
private final InvariantDeviceProfile mIdp;
|
private final InvariantDeviceProfile mIdp;
|
||||||
private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
|
private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
|
||||||
@@ -145,6 +148,14 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
return this;
|
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
|
* Find a cached object from mObjectMap if we have already created one. If not, generate
|
||||||
* an object using the provider.
|
* an object using the provider.
|
||||||
@@ -349,6 +360,9 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
|
private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
|
||||||
WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
|
WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
|
||||||
info.providerName);
|
info.providerName);
|
||||||
|
if (widgetItem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
AppWidgetHostView view = new AppWidgetHostView(mContext);
|
AppWidgetHostView view = new AppWidgetHostView(mContext);
|
||||||
view.setAppWidget(-1, widgetItem.widgetInfo);
|
view.setAppWidget(-1, widgetItem.widgetInfo);
|
||||||
view.updateAppWidget(null);
|
view.updateAppWidget(null);
|
||||||
@@ -385,9 +399,11 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorkspaceFetcher fetcher;
|
WorkspaceFetcher fetcher;
|
||||||
|
PreviewContext previewContext = null;
|
||||||
if (needsToMigrate && success) {
|
if (needsToMigrate && success) {
|
||||||
|
previewContext = new PreviewContext(mContext, mIdp);
|
||||||
LauncherAppState appForPreview = new LauncherAppState(
|
LauncherAppState appForPreview = new LauncherAppState(
|
||||||
new PreviewContext(mContext, mIdp), null /* iconCacheFileName */);
|
previewContext, null /* iconCacheFileName */);
|
||||||
fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
|
fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
|
||||||
MODEL_EXECUTOR.execute(fetcher);
|
MODEL_EXECUTOR.execute(fetcher);
|
||||||
} else {
|
} else {
|
||||||
@@ -396,6 +412,9 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
(LauncherModel.ModelUpdateTask) fetcher);
|
(LauncherModel.ModelUpdateTask) fetcher);
|
||||||
}
|
}
|
||||||
WorkspaceResult workspaceResult = fetcher.get();
|
WorkspaceResult workspaceResult = fetcher.get();
|
||||||
|
if (previewContext != null) {
|
||||||
|
previewContext.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
if (workspaceResult == null) {
|
if (workspaceResult == null) {
|
||||||
return;
|
return;
|
||||||
@@ -557,6 +576,7 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
|||||||
public WorkspaceResult call() throws Exception {
|
public WorkspaceResult call() throws Exception {
|
||||||
List<ShortcutInfo> allShortcuts = new ArrayList<>();
|
List<ShortcutInfo> allShortcuts = new ArrayList<>();
|
||||||
loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI);
|
loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI);
|
||||||
|
mBgDataModel.widgetsModel.update(mApp, null);
|
||||||
return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets,
|
return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets,
|
||||||
mBgDataModel.widgetsModel);
|
mBgDataModel.widgetsModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public final class FileLog {
|
|||||||
private static final DateFormat DATE_FORMAT =
|
private static final DateFormat DATE_FORMAT =
|
||||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
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 Handler sHandler = null;
|
||||||
private static File sLogsDirectory = null;
|
private static File sLogsDirectory = null;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ import java.util.concurrent.CancellationException;
|
|||||||
public class LoaderTask implements Runnable {
|
public class LoaderTask implements Runnable {
|
||||||
private static final String TAG = "LoaderTask";
|
private static final String TAG = "LoaderTask";
|
||||||
|
|
||||||
private final LauncherAppState mApp;
|
protected final LauncherAppState mApp;
|
||||||
private final AllAppsList mBgAllAppsList;
|
private final AllAppsList mBgAllAppsList;
|
||||||
protected final BgDataModel mBgDataModel;
|
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
|
// SingleAxisSwipeDetector.Listener's
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) { }
|
public void onDragStart(boolean start, float startDisplacement) { }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
|
|||||||
|
|
||||||
initFlags();
|
initFlags();
|
||||||
loadPluginPrefs();
|
loadPluginPrefs();
|
||||||
|
maybeAddSandboxCategory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
private String toName(String action) {
|
||||||
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
|
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
|
||||||
.replace("com.android.launcher3.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_LOCKED;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
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.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
|
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;
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.content.res.Resources;
|
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 android.view.WindowManager;
|
||||||
|
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.util.UiThreadHelper;
|
import com.android.launcher3.util.UiThreadHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to manage launcher rotation
|
* 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 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() {
|
public static boolean getAllowRotationDefaultValue() {
|
||||||
// If the device was scaled, used the original dimensions to determine if rotation
|
// If the device's pixel density was scaled (usually via settings for A11y), use the
|
||||||
// is allowed of not.
|
// original dimensions to determine if rotation is allowed of not.
|
||||||
Resources res = Resources.getSystem();
|
Resources res = Resources.getSystem();
|
||||||
int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
|
int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
|
||||||
* res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
|
* res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
|
||||||
return originalSmallestWidth >= 600;
|
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_NONE = 0;
|
||||||
public static final int REQUEST_ROTATE = 1;
|
public static final int REQUEST_ROTATE = 1;
|
||||||
public static final int REQUEST_LOCK = 2;
|
public static final int REQUEST_LOCK = 2;
|
||||||
@@ -56,6 +95,8 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
private boolean mIgnoreAutoRotateSettings;
|
private boolean mIgnoreAutoRotateSettings;
|
||||||
private boolean mAutoRotateEnabled;
|
private boolean mAutoRotateEnabled;
|
||||||
|
private boolean mForcedRotation;
|
||||||
|
private List<ForcedRotationChangedListener> mForcedRotationChangedListeners = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotation request made by
|
* Rotation request made by
|
||||||
@@ -84,6 +125,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
// On large devices we do not handle auto-rotate differently.
|
// On large devices we do not handle auto-rotate differently.
|
||||||
mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
|
mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
|
||||||
|
updateForcedRotation();
|
||||||
if (!mIgnoreAutoRotateSettings) {
|
if (!mIgnoreAutoRotateSettings) {
|
||||||
mPrefs = Utilities.getPrefs(mLauncher);
|
mPrefs = Utilities.getPrefs(mLauncher);
|
||||||
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
@@ -92,6 +134,26 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
|||||||
} else {
|
} else {
|
||||||
mPrefs = null;
|
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) {
|
public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
|
||||||
@@ -173,6 +235,10 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
|||||||
if (mPrefs != null) {
|
if (mPrefs != null) {
|
||||||
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
if (mContentResolver != null) {
|
||||||
|
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||||
|
}
|
||||||
|
mForcedRotationChangedListeners.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +248,10 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int activityFlags;
|
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 ?
|
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
|
||||||
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
|
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
|
} 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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
|
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ public abstract class AbstractStateChangeTouchController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) {
|
||||||
mStartState = mLauncher.getStateManager().getState();
|
mStartState = mLauncher.getStateManager().getState();
|
||||||
mIsLogContainerSet = false;
|
mIsLogContainerSet = false;
|
||||||
if (mCurrentAnimation == null) {
|
if (mCurrentAnimation == null) {
|
||||||
|
|||||||
@@ -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
|
@Override
|
||||||
protected void reportDragStartInternal(boolean recatch) {
|
protected void reportDragStartInternal(boolean recatch) {
|
||||||
mListener.onDragStart(!recatch);
|
float startDisplacement = mDir.extractDirection(mSubtractDisplacement);
|
||||||
|
mListener.onDragStart(!recatch, startDisplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,8 +166,13 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector {
|
|||||||
|
|
||||||
/** Listener to receive updates on the swipe. */
|
/** Listener to receive updates on the swipe. */
|
||||||
public interface Listener {
|
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);
|
boolean onDrag(float displacement);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import android.util.Log;
|
|||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,6 +129,18 @@ public class DefaultDisplay implements DisplayListener {
|
|||||||
|
|
||||||
public final DisplayMetrics metrics;
|
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) {
|
private Info(Context context) {
|
||||||
this(context.getSystemService(WindowManager.class).getDefaultDisplay());
|
this(context.getSystemService(WindowManager.class).getDefaultDisplay());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ public class DynamicResource implements ResourceProvider, PluginListener<Resourc
|
|||||||
return mContext.getResources().getColor(resId, null);
|
return mContext.getResources().getColor(resId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFloat(@DimenRes int resId) {
|
||||||
|
return mContext.getResources().getFloat(resId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginConnected(ResourceProvider plugin, Context context) {
|
public void onPluginConnected(ResourceProvider plugin, Context context) {
|
||||||
mPlugin = plugin;
|
mPlugin = plugin;
|
||||||
|
|||||||
@@ -26,11 +26,13 @@ import android.view.ViewConfiguration;
|
|||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
|
||||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||||
import androidx.dynamicanimation.animation.SpringForce;
|
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
|
* Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
|
||||||
* customization options.
|
* customization options.
|
||||||
@@ -425,6 +427,7 @@ public class OverScroller {
|
|||||||
// Current state of the animation.
|
// Current state of the animation.
|
||||||
private int mState = SPLINE;
|
private int mState = SPLINE;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
private SpringAnimation mSpring;
|
private SpringAnimation mSpring;
|
||||||
|
|
||||||
// Constant gravity value, used in the deceleration phase.
|
// Constant gravity value, used in the deceleration phase.
|
||||||
@@ -500,6 +503,7 @@ public class OverScroller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SplineOverScroller(Context context) {
|
SplineOverScroller(Context context) {
|
||||||
|
mContext = context;
|
||||||
mFinished = true;
|
mFinished = true;
|
||||||
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
|
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
|
||||||
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
|
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
|
||||||
@@ -560,9 +564,12 @@ public class OverScroller {
|
|||||||
}
|
}
|
||||||
mSpring = new SpringAnimation(this, SPRING_PROPERTY);
|
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)
|
mSpring.setSpring(new SpringForce(mFinal)
|
||||||
.setStiffness(SpringForce.STIFFNESS_LOW)
|
.setStiffness(stiffness)
|
||||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
.setDampingRatio(damping));
|
||||||
mSpring.setStartVelocity(velocity);
|
mSpring.setStartVelocity(velocity);
|
||||||
mSpring.animateToFinalPosition(mFinal);
|
mSpring.animateToFinalPosition(mFinal);
|
||||||
mSpring.addEndListener((animation, canceled, value, velocity1) -> {
|
mSpring.addEndListener((animation, canceled, value, velocity1) -> {
|
||||||
|
|||||||
@@ -149,8 +149,7 @@ public abstract class AbstractSlideInView extends AbstractFloatingView
|
|||||||
/* SingleAxisSwipeDetector.Listener */
|
/* SingleAxisSwipeDetector.Listener */
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(boolean start) {
|
public void onDragStart(boolean start, float startDisplacement) { }
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onDrag(float displacement) {
|
public boolean onDrag(float displacement) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.util.TypedValue;
|
|||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.FastBitmapDrawable;
|
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
|
@Override
|
||||||
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
|
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
|
||||||
int maxHeight) {
|
int maxHeight) {
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ import java.util.stream.Stream;
|
|||||||
*/
|
*/
|
||||||
public class WidgetManagerHelper {
|
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 AppWidgetManager mAppWidgetManager;
|
||||||
final Context mContext;
|
final Context mContext;
|
||||||
|
|
||||||
@@ -127,6 +130,14 @@ public class WidgetManagerHelper {
|
|||||||
return null;
|
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) {
|
public static Map<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap(Context context) {
|
||||||
if (WidgetsModel.GO_DISABLE_WIDGETS) {
|
if (WidgetsModel.GO_DISABLE_WIDGETS) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
|||||||
public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
|
public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
|
||||||
new MainThreadInitializedObject<>(CustomWidgetManager::new);
|
new MainThreadInitializedObject<>(CustomWidgetManager::new);
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
/**
|
/**
|
||||||
* auto provider Id is an ever-increasing number that serves as the providerId whenever a new
|
* auto provider Id is an ever-increasing number that serves as the providerId whenever a new
|
||||||
* custom widget has been connected.
|
* custom widget has been connected.
|
||||||
@@ -62,6 +63,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
|||||||
private Consumer<PackageUserKey> mWidgetRefreshCallback;
|
private Consumer<PackageUserKey> mWidgetRefreshCallback;
|
||||||
|
|
||||||
private CustomWidgetManager(Context context) {
|
private CustomWidgetManager(Context context) {
|
||||||
|
mContext = context;
|
||||||
mPlugins = new SparseArray<>();
|
mPlugins = new SparseArray<>();
|
||||||
mCustomWidgets = new ArrayList<>();
|
mCustomWidgets = new ArrayList<>();
|
||||||
mWidgetsIdMap = new SparseArray<>();
|
mWidgetsIdMap = new SparseArray<>();
|
||||||
@@ -69,6 +71,10 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
|
|||||||
.addPluginListener(this, CustomWidgetPlugin.class, true);
|
.addPluginListener(this, CustomWidgetPlugin.class, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onDestroy() {
|
||||||
|
PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
|
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
|
||||||
mPlugins.put(mAutoProviderId, plugin);
|
mPlugins.put(mAutoProviderId, plugin);
|
||||||
|
|||||||
@@ -44,4 +44,9 @@ public interface ResourceProvider extends Plugin {
|
|||||||
* @see android.content.res.Resources#getColor(int)
|
* @see android.content.res.Resources#getColor(int)
|
||||||
*/
|
*/
|
||||||
int getColor(int resId);
|
int getColor(int resId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see android.content.res.Resources#getFloat(int)
|
||||||
|
*/
|
||||||
|
float getFloat(int resId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ public class WidgetsModel {
|
|||||||
ComponentName providerName) {
|
ComponentName providerName) {
|
||||||
ArrayList<WidgetItem> widgetsList = mWidgetsList.get(
|
ArrayList<WidgetItem> widgetsList = mWidgetsList.get(
|
||||||
new PackageItemInfo(providerName.getPackageName()));
|
new PackageItemInfo(providerName.getPackageName()));
|
||||||
|
if (widgetsList == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
for (WidgetItem item : widgetsList) {
|
for (WidgetItem item : widgetsList) {
|
||||||
if (item.componentName.equals(providerName)) {
|
if (item.componentName.equals(providerName)) {
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100, 100 - mTouchSlop);
|
mGenerator.move(0, 100, 100 - mTouchSlop);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,7 +99,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100, 100 + mTouchSlop);
|
mGenerator.move(0, 100, 100 + mTouchSlop);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -107,7 +107,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener, never()).onDragStart(anyBoolean());
|
verify(mMockListener, never()).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -118,7 +118,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -129,7 +129,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100 - mTouchSlop, 100);
|
mGenerator.move(0, 100 - mTouchSlop, 100);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -140,7 +140,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100 - mTouchSlop, 100);
|
mGenerator.move(0, 100 - mTouchSlop, 100);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -151,7 +151,7 @@ public class SingleAxisSwipeDetectorTest {
|
|||||||
mGenerator.put(0, 100, 100);
|
mGenerator.put(0, 100, 100);
|
||||||
mGenerator.move(0, 100 + mTouchSlop, 100);
|
mGenerator.move(0, 100 + mTouchSlop, 100);
|
||||||
// TODO: actually calculate the following parameters and do exact value checks.
|
// TODO: actually calculate the following parameters and do exact value checks.
|
||||||
verify(mMockListener).onDragStart(anyBoolean());
|
verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -34,10 +34,13 @@ import android.content.IntentFilter;
|
|||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.LauncherActivityInfo;
|
import android.content.pm.LauncherActivityInfo;
|
||||||
import android.content.pm.LauncherApps;
|
import android.content.pm.LauncherApps;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Debug;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import androidx.test.uiautomator.By;
|
import androidx.test.uiautomator.By;
|
||||||
@@ -68,6 +71,7 @@ import com.android.launcher3.util.rule.ShellCommandRule;
|
|||||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.rules.RuleChain;
|
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.
|
// so let's just mark the fact that the leak has happened.
|
||||||
if (sDetectedActivityLeak == null) {
|
if (sDetectedActivityLeak == null) {
|
||||||
sDetectedActivityLeak = violation.toString();
|
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());
|
StrictMode.setVmPolicy(builder.build());
|
||||||
@@ -126,18 +138,6 @@ public abstract class AbstractLauncherUiTest {
|
|||||||
public static void checkDetectedLeaks() {
|
public static void checkDetectedLeaks() {
|
||||||
if (sDetectedActivityLeak != null && !sActivityLeakReported) {
|
if (sDetectedActivityLeak != null && !sActivityLeakReported) {
|
||||||
sActivityLeakReported = true;
|
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
|
@Before
|
||||||
public void setUp() throws Exception {
|
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;
|
mLauncherPid = 0;
|
||||||
// Disable app tracker
|
// Disable app tracker
|
||||||
AppLaunchTracker.INSTANCE.initializeForTesting(new AppLaunchTracker());
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetHost;
|
import android.appwidget.AppWidgetHost;
|
||||||
@@ -33,6 +34,7 @@ import android.content.pm.PackageInstaller.SessionParams;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
@@ -41,6 +43,7 @@ import com.android.launcher3.LauncherAppWidgetHost;
|
|||||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.pm.InstallSessionHelper;
|
import com.android.launcher3.pm.InstallSessionHelper;
|
||||||
import com.android.launcher3.tapl.Workspace;
|
import com.android.launcher3.tapl.Workspace;
|
||||||
import com.android.launcher3.ui.AbstractLauncherUiTest;
|
import com.android.launcher3.ui.AbstractLauncherUiTest;
|
||||||
@@ -86,7 +89,8 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||||||
|
|
||||||
// Clear all existing data
|
// Clear all existing data
|
||||||
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
|
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
|
@After
|
||||||
@@ -172,6 +176,26 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||||||
assertNotNull(AppWidgetManager.getInstance(mTargetContext)
|
assertNotNull(AppWidgetManager.getInstance(mTargetContext)
|
||||||
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
|
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
|
||||||
LauncherSettings.Favorites.APPWIDGET_ID))));
|
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
|
@Test
|
||||||
@@ -254,6 +278,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a LauncherAppWidgetInfo corresponding to {@param info}
|
* Creates a LauncherAppWidgetInfo corresponding to {@param info}
|
||||||
|
*
|
||||||
* @param bindWidget if true the info is bound and a valid widgetId is assigned to
|
* @param bindWidget if true the info is bound and a valid widgetId is assigned to
|
||||||
* the LauncherAppWidgetInfo
|
* the LauncherAppWidgetInfo
|
||||||
*/
|
*/
|
||||||
@@ -306,7 +331,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||||||
.keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName));
|
.keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName));
|
||||||
return packages;
|
return packages;
|
||||||
});
|
});
|
||||||
while(true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
mTargetContext.getPackageManager().getPackageInfo(
|
mTargetContext.getPackageManager().getPackageInfo(
|
||||||
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
|
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||||
@@ -316,7 +341,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkg = invalidPackage + count;
|
pkg = invalidPackage + count;
|
||||||
count ++;
|
count++;
|
||||||
}
|
}
|
||||||
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(10,
|
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(10,
|
||||||
new ComponentName(pkg, "com.test.widgetprovider"));
|
new ComponentName(pkg, "com.test.widgetprovider"));
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public class SimpleActivityRule<T extends Activity> implements TestRule {
|
|||||||
mBase.evaluate();
|
mBase.evaluate();
|
||||||
} finally {
|
} finally {
|
||||||
app.unregisterActivityLifecycleCallbacks(this);
|
app.unregisterActivityLifecycleCallbacks(this);
|
||||||
|
mActivity = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public final class LauncherInstrumentation {
|
|||||||
|
|
||||||
private static final String WORKSPACE_RES_ID = "workspace";
|
private static final String WORKSPACE_RES_ID = "workspace";
|
||||||
private static final String APPS_RES_ID = "apps_view";
|
private static final String APPS_RES_ID = "apps_view";
|
||||||
private static final String OVERVIEW_RES_ID = "overview_panel_recents";
|
private static final String OVERVIEW_RES_ID = "overview_panel";
|
||||||
private static final String WIDGETS_RES_ID = "widgets_list_view";
|
private static final String WIDGETS_RES_ID = "widgets_list_view";
|
||||||
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
|
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
|
||||||
public static final int WAIT_TIME_MS = 10000;
|
public static final int WAIT_TIME_MS = 10000;
|
||||||
@@ -331,21 +331,25 @@ public final class LauncherInstrumentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getSystemAnomalyMessage() {
|
private String getSystemAnomalyMessage() {
|
||||||
UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
|
try {
|
||||||
if (object != null) {
|
UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
|
||||||
return "System alert popup is visible: " + object.getText();
|
if (object != null) {
|
||||||
|
return "System alert popup is visible: " + object.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
object = mDevice.findObject(By.res("android", "message"));
|
||||||
|
if (object != null) {
|
||||||
|
return "Message popup by " + object.getApplicationPackage() + " is visible: "
|
||||||
|
+ object.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
|
||||||
|
|
||||||
|
if (!mDevice.hasObject(By.textStartsWith(""))) return "Screen is empty";
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.w(TAG, "getSystemAnomalyMessage failed", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
object = mDevice.findObject(By.res("android", "message"));
|
|
||||||
if (object != null) {
|
|
||||||
return "Message popup by " + object.getApplicationPackage() + " is visible: "
|
|
||||||
+ object.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
|
|
||||||
|
|
||||||
if (!mDevice.hasObject(By.textStartsWith(""))) return "Screen is empty";
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user