Snap for 5110273 from e5aa6c5f60 to qt-release
Change-Id: Iea4e4fc8ee69071ca41f17290220eb3d7237a18f
This commit is contained in:
+2
-1
@@ -13,4 +13,5 @@ bin/
|
||||
local.properties
|
||||
gradle/
|
||||
build/
|
||||
gradlew*
|
||||
gradlew*
|
||||
.DS_Store
|
||||
|
||||
+5
-3
@@ -101,6 +101,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, src_shortcuts_overrides) \
|
||||
$(call all-java-files-under, src_ui_overrides) \
|
||||
$(call all-java-files-under, src_flags)
|
||||
|
||||
@@ -131,7 +132,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, src_ui_overrides) \
|
||||
$(call all-java-files-under, go/src_flags)
|
||||
$(call all-java-files-under, go/src)
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/go/res
|
||||
|
||||
@@ -174,7 +175,8 @@ LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, quickstep/src) \
|
||||
$(call all-java-files-under, src_flags)
|
||||
$(call all-java-files-under, src_flags) \
|
||||
$(call all-java-files-under, src_shortcuts_overrides)
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
@@ -235,7 +237,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, quickstep/src) \
|
||||
$(call all-java-files-under, go/src_flags)
|
||||
$(call all-java-files-under, go/src)
|
||||
|
||||
LOCAL_RESOURCE_DIR := \
|
||||
$(LOCAL_PATH)/quickstep/res \
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ android {
|
||||
sourceSets {
|
||||
main {
|
||||
res.srcDirs = ['res']
|
||||
java.srcDirs = ['src']
|
||||
java.srcDirs = ['src', 'src_shortcuts_overrides']
|
||||
manifest.srcFile 'AndroidManifest-common.xml'
|
||||
proto {
|
||||
srcDir 'protos/'
|
||||
@@ -100,7 +100,7 @@ android {
|
||||
|
||||
l3go {
|
||||
res.srcDirs = ['go/res']
|
||||
java.srcDirs = ['go/src_flags', "src_ui_overrides"]
|
||||
java.srcDirs = ['go/src', "src_ui_overrides"]
|
||||
manifest.srcFile "go/AndroidManifest.xml"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.shortcuts;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
|
||||
*/
|
||||
public class DeepShortcutManager {
|
||||
private static DeepShortcutManager sInstance;
|
||||
private static final Object sInstanceLock = new Object();
|
||||
|
||||
public static DeepShortcutManager getInstance(Context context) {
|
||||
synchronized (sInstanceLock) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new DeepShortcutManager(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
}
|
||||
|
||||
private DeepShortcutManager(Context context) {
|
||||
}
|
||||
|
||||
public static boolean supportsShortcuts(ItemInfo info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean wasLastCallSuccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for the shortcuts with the package name and provided ids.
|
||||
*
|
||||
* This method is intended to get the full details for shortcuts when they are added or updated,
|
||||
* because we only get "key" fields in onShortcutsChanged().
|
||||
*/
|
||||
public List<ShortcutInfoCompat> queryForFullDetails(String packageName,
|
||||
List<String> shortcutIds, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
|
||||
* to be displayed in the shortcuts container on long press.
|
||||
*/
|
||||
public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
|
||||
UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given shortcut from the current list of pinned shortcuts.
|
||||
* (Runs on background thread)
|
||||
*/
|
||||
public void unpinShortcut(final ShortcutKey key) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given shortcut to the current list of pinned shortcuts.
|
||||
* (Runs on background thread)
|
||||
*/
|
||||
public void pinShortcut(final ShortcutKey key) {
|
||||
}
|
||||
|
||||
public void startShortcut(String packageName, String id, Rect sourceBounds,
|
||||
Bundle startActivityOptions, UserHandle user) {
|
||||
}
|
||||
|
||||
public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id's of pinned shortcuts associated with the given package and user.
|
||||
*
|
||||
* If packageName is null, returns all pinned shortcuts regardless of package.
|
||||
*/
|
||||
public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName,
|
||||
List<String> shortcutIds, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public boolean hasHostPermission() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -178,6 +178,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
@Override
|
||||
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
|
||||
if (hasControlRemoteAppTransitionPermission()) {
|
||||
boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
|
||||
&& findTaskViewToLaunch(launcher, v, null) != null;
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
if (fromRecents && recentsView.getQuickScrubController().isQuickSwitch()) {
|
||||
return ActivityOptions.makeCustomAnimation(mLauncher, R.anim.no_anim,
|
||||
R.anim.no_anim);
|
||||
}
|
||||
|
||||
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
|
||||
true /* startAtFrontOfQueue */) {
|
||||
|
||||
@@ -218,8 +226,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
}
|
||||
};
|
||||
|
||||
boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
|
||||
&& findTaskViewToLaunch(launcher, v, null) != null;
|
||||
int duration = fromRecents
|
||||
? RECENTS_LAUNCH_DURATION
|
||||
: APP_LAUNCH_DURATION;
|
||||
|
||||
@@ -35,6 +35,7 @@ public class FastOverviewState extends OverviewState {
|
||||
* Vertical transition of the task previews relative to the full container.
|
||||
*/
|
||||
public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f;
|
||||
public static final float OVERVIEW_CENTERED_TRANSLATION_FACTOR = 0.5f;
|
||||
|
||||
private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION
|
||||
| FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY;
|
||||
@@ -60,12 +61,17 @@ public class FastOverviewState extends OverviewState {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
recentsView.getTaskSize(sTempRect);
|
||||
|
||||
return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher),
|
||||
OVERVIEW_TRANSLATION_FACTOR};
|
||||
boolean isQuickSwitch = recentsView.getQuickScrubController().isQuickSwitch();
|
||||
float translationYFactor = isQuickSwitch
|
||||
? OVERVIEW_CENTERED_TRANSLATION_FACTOR
|
||||
: OVERVIEW_TRANSLATION_FACTOR;
|
||||
return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher,
|
||||
isQuickSwitch), translationYFactor};
|
||||
}
|
||||
|
||||
public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) {
|
||||
if (dp.isVerticalBarLayout()) {
|
||||
public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context,
|
||||
boolean isQuickSwitch) {
|
||||
if (dp.isVerticalBarLayout() && !isQuickSwitch) {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@@ -73,6 +79,10 @@ public class FastOverviewState extends OverviewState {
|
||||
float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin);
|
||||
float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing)
|
||||
+ res.getDimension(R.dimen.quickscrub_adjacent_visible_width));
|
||||
if (isQuickSwitch) {
|
||||
usedWidth = taskRect.width();
|
||||
return Math.max(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth);
|
||||
}
|
||||
return Math.min(Math.min(dp.availableHeightPx / usedHeight,
|
||||
dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.View.TRANSLATION_Y;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
@@ -58,6 +57,7 @@ import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.uioverrides.FastOverviewState;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -192,7 +192,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
@InteractionType int interactionType, TransformedRect outRect) {
|
||||
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect);
|
||||
if (interactionType == INTERACTION_QUICK_SCRUB) {
|
||||
outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context);
|
||||
outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context,
|
||||
FeatureFlags.QUICK_SWITCH.get());
|
||||
}
|
||||
if (dp.isVerticalBarLayout()) {
|
||||
Rect targetInsets = dp.getInsets();
|
||||
|
||||
@@ -16,8 +16,18 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.animation.Interpolator;
|
||||
@@ -37,8 +47,10 @@ import com.android.quickstep.views.TaskView;
|
||||
* The behavior is to evenly divide the progress into sections, each of which scrolls one page.
|
||||
* The first and last section set an alarm to auto-advance backwards or forwards, respectively.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class QuickScrubController implements OnAlarmListener {
|
||||
|
||||
public static final int QUICK_SWITCH_FROM_APP_START_DURATION = 0;
|
||||
public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240;
|
||||
public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200;
|
||||
// We want the translation y to finish faster than the rest of the animation.
|
||||
@@ -52,6 +64,19 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f
|
||||
};
|
||||
|
||||
private static final FloatProperty<QuickScrubController> PROGRESS
|
||||
= new FloatProperty<QuickScrubController>("progress") {
|
||||
@Override
|
||||
public void setValue(QuickScrubController quickScrubController, float progress) {
|
||||
quickScrubController.onQuickScrubProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(QuickScrubController quickScrubController) {
|
||||
return quickScrubController.mEndProgress;
|
||||
}
|
||||
};
|
||||
|
||||
private static final String TAG = "QuickScrubController";
|
||||
private static final boolean ENABLE_AUTO_ADVANCE = true;
|
||||
private static final long AUTO_ADVANCE_DELAY = 500;
|
||||
@@ -72,6 +97,13 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
private ActivityControlHelper mActivityControlHelper;
|
||||
private TouchInteractionLog mTouchInteractionLog;
|
||||
|
||||
private boolean mIsQuickSwitch;
|
||||
private float mStartProgress;
|
||||
private float mEndProgress;
|
||||
private float mPrevProgressDelta;
|
||||
private float mPrevPrevProgressDelta;
|
||||
private boolean mShouldSwitchToNext;
|
||||
|
||||
public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
|
||||
mActivity = activity;
|
||||
mRecentsView = recentsView;
|
||||
@@ -91,17 +123,26 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
mActivityControlHelper = controlHelper;
|
||||
mTouchInteractionLog = touchInteractionLog;
|
||||
|
||||
if (mIsQuickSwitch) {
|
||||
mShouldSwitchToNext = true;
|
||||
mPrevProgressDelta = 0;
|
||||
if (mRecentsView.getTaskViewCount() > 0) {
|
||||
mRecentsView.getTaskViewAt(0).setFullscreen(true);
|
||||
}
|
||||
if (mRecentsView.getTaskViewCount() > 1) {
|
||||
mRecentsView.getTaskViewAt(1).setFullscreen(true);
|
||||
}
|
||||
}
|
||||
|
||||
snapToNextTaskIfAvailable();
|
||||
mActivity.getUserEventDispatcher().resetActionDurationMillis();
|
||||
}
|
||||
|
||||
public void onQuickScrubEnd() {
|
||||
mInQuickScrub = false;
|
||||
if (ENABLE_AUTO_ADVANCE) {
|
||||
mAutoAdvanceAlarm.cancelAlarm();
|
||||
}
|
||||
int page = mRecentsView.getNextPage();
|
||||
|
||||
Runnable launchTaskRunnable = () -> {
|
||||
int page = mRecentsView.getPageNearestToCenterOfScreen();
|
||||
TaskView taskView = mRecentsView.getTaskViewAt(page);
|
||||
if (taskView != null) {
|
||||
mWaitingForTaskLaunch = true;
|
||||
@@ -118,12 +159,49 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key));
|
||||
}
|
||||
mWaitingForTaskLaunch = false;
|
||||
if (mIsQuickSwitch) {
|
||||
mIsQuickSwitch = false;
|
||||
if (mRecentsView.getTaskViewCount() > 0) {
|
||||
mRecentsView.getTaskViewAt(0).setFullscreen(false);
|
||||
}
|
||||
if (mRecentsView.getTaskViewCount() > 1) {
|
||||
mRecentsView.getTaskViewAt(1).setFullscreen(false);
|
||||
}
|
||||
}
|
||||
|
||||
}, taskView.getHandler());
|
||||
} else {
|
||||
breakOutOfQuickScrub();
|
||||
}
|
||||
mActivityControlHelper = null;
|
||||
};
|
||||
|
||||
if (mIsQuickSwitch) {
|
||||
float progressVelocity = mPrevPrevProgressDelta / SINGLE_FRAME_MS;
|
||||
// Move to the next frame immediately, then start the animation from the
|
||||
// following frame since it starts a frame later.
|
||||
float singleFrameProgress = progressVelocity * SINGLE_FRAME_MS;
|
||||
float fromProgress = mEndProgress + singleFrameProgress;
|
||||
onQuickScrubProgress(fromProgress);
|
||||
fromProgress += singleFrameProgress;
|
||||
float toProgress = mShouldSwitchToNext ? 1 : 0;
|
||||
int duration = (int) Math.abs((toProgress - fromProgress) / progressVelocity);
|
||||
duration = Utilities.boundToRange(duration, 80, 300);
|
||||
Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, fromProgress, toProgress);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
launchTaskRunnable.run();
|
||||
}
|
||||
});
|
||||
anim.setDuration(duration).start();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ENABLE_AUTO_ADVANCE) {
|
||||
mAutoAdvanceAlarm.cancelAlarm();
|
||||
}
|
||||
int page = mRecentsView.getNextPage();
|
||||
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
|
||||
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
|
||||
if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) {
|
||||
@@ -151,19 +229,28 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
mLaunchingTaskId = 0;
|
||||
}
|
||||
|
||||
public boolean prepareQuickScrub(String tag) {
|
||||
return prepareQuickScrub(tag, mIsQuickSwitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the UI for quick scrub, returns true if success.
|
||||
*/
|
||||
public boolean prepareQuickScrub(String tag) {
|
||||
public boolean prepareQuickScrub(String tag, boolean isQuickSwitch) {
|
||||
if (mWaitingForTaskLaunch || mInQuickScrub) {
|
||||
Log.d(tag, "Waiting for last scrub to finish, will skip this interaction");
|
||||
return false;
|
||||
}
|
||||
mOnFinishedTransitionToQuickScrubRunnable = null;
|
||||
mRecentsView.setNextPageSwitchRunnable(null);
|
||||
mIsQuickSwitch = isQuickSwitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isQuickSwitch() {
|
||||
return mIsQuickSwitch;
|
||||
}
|
||||
|
||||
public boolean isWaitingForTaskLaunch() {
|
||||
return mWaitingForTaskLaunch;
|
||||
}
|
||||
@@ -179,6 +266,40 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
}
|
||||
|
||||
public void onQuickScrubProgress(float progress) {
|
||||
if (mIsQuickSwitch) {
|
||||
TaskView currentPage = mRecentsView.getTaskViewAt(0);
|
||||
TaskView nextPage = mRecentsView.getTaskViewAt(1);
|
||||
if (currentPage == null || nextPage == null) {
|
||||
return;
|
||||
}
|
||||
if (!mFinishedTransitionToQuickScrub) {
|
||||
mStartProgress = mEndProgress = progress;
|
||||
} else {
|
||||
float progressDelta = progress - mEndProgress;
|
||||
mEndProgress = progress;
|
||||
progress = Utilities.boundToRange(progress, mStartProgress, 1);
|
||||
progress = Utilities.mapToRange(progress, mStartProgress, 1, 0, 1, LINEAR);
|
||||
if (mInQuickScrub) {
|
||||
mShouldSwitchToNext = mPrevProgressDelta > 0.007f || progressDelta > 0.007f
|
||||
|| progress >= 0.5f;
|
||||
}
|
||||
mPrevPrevProgressDelta = mPrevProgressDelta;
|
||||
mPrevProgressDelta = progressDelta;
|
||||
float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing();
|
||||
int scrollDir = mRecentsView.isRtl() ? -1 : 1;
|
||||
int linearScrollDiff = (int) (progress * scrollDiff * scrollDir);
|
||||
float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir;
|
||||
currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress)
|
||||
* TaskView.EDGE_SCALE_DOWN_FACTOR);
|
||||
currentPage.setTranslationX(linearScrollDiff + accelScrollDiff);
|
||||
nextPage.setTranslationZ(1);
|
||||
nextPage.setTranslationY(currentPage.getTranslationY());
|
||||
int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0;
|
||||
mRecentsView.setScrollX(startScroll + linearScrollDiff);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int quickScrubSection = 0;
|
||||
for (float threshold : QUICK_SCRUB_THRESHOLDS) {
|
||||
if (progress < threshold) {
|
||||
@@ -228,9 +349,14 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
|
||||
public void snapToNextTaskIfAvailable() {
|
||||
if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
|
||||
int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
|
||||
: QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
|
||||
int duration = mIsQuickSwitch
|
||||
? QUICK_SWITCH_FROM_APP_START_DURATION
|
||||
: mStartedFromHome
|
||||
? QUICK_SCRUB_FROM_HOME_START_DURATION
|
||||
: QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
int pageToGoTo = mStartedFromHome || mIsQuickSwitch
|
||||
? 0
|
||||
: mRecentsView.getNextPage() + 1;
|
||||
goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
|
||||
QUICK_SCRUB_START_INTERPOLATOR);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_FROM_APP_START_DURATION;
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
@@ -59,6 +60,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -979,12 +981,14 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
|
||||
|
||||
// Start the window animation without waiting for launcher.
|
||||
animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR,
|
||||
true /* goingToHome */);
|
||||
long duration = FeatureFlags.QUICK_SWITCH.get()
|
||||
? QUICK_SWITCH_FROM_APP_START_DURATION
|
||||
: QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
animateToProgress(mCurrentShift.value, 1f, duration, LINEAR, true /* goingToHome */);
|
||||
}
|
||||
|
||||
private void onQuickScrubStartUi() {
|
||||
if (!mQuickScrubController.prepareQuickScrub(TAG)) {
|
||||
if (!mQuickScrubController.prepareQuickScrub(TAG, FeatureFlags.QUICK_SWITCH.get())) {
|
||||
mQuickScrubBlocked = true;
|
||||
setStateOnUiThread(STATE_RESUME_LAST_TASK | STATE_HANDLER_INVALIDATED);
|
||||
return;
|
||||
@@ -993,6 +997,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
mLauncherTransitionController.getAnimationPlayer().end();
|
||||
mLauncherTransitionController = null;
|
||||
}
|
||||
mLayoutListener.finish();
|
||||
|
||||
mActivityControlHelper.onQuickInteractionStart(mActivity, mRunningTaskInfo, false,
|
||||
mTouchInteractionLog);
|
||||
@@ -1008,6 +1013,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
mQuickScrubController.onFinishedTransitionToQuickScrub();
|
||||
|
||||
mRecentsView.animateUpRunningTaskIconScale();
|
||||
if (mQuickScrubController.isQuickSwitch()) {
|
||||
TaskView runningTask = mRecentsView.getRunningTaskView();
|
||||
if (runningTask != null) {
|
||||
runningTask.setTranslationY(-mActivity.getResources().getDimension(
|
||||
R.dimen.task_thumbnail_half_top_margin) * 1f / mRecentsView.getScaleX());
|
||||
}
|
||||
}
|
||||
RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -33,7 +32,7 @@ import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
@@ -78,6 +77,7 @@ public class TaskThumbnailView extends View {
|
||||
private final Matrix mMatrix = new Matrix();
|
||||
|
||||
private float mClipBottom = -1;
|
||||
private Rect mScaledInsets = new Rect();
|
||||
|
||||
private Task mTask;
|
||||
private ThumbnailData mThumbnailData;
|
||||
@@ -179,7 +179,17 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
|
||||
if (((TaskView) getParent()).isFullscreen()) {
|
||||
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
|
||||
drawOnCanvas(canvas,
|
||||
-mScaledInsets.left,
|
||||
-mScaledInsets.top,
|
||||
getMeasuredWidth() + mScaledInsets.right,
|
||||
getMeasuredHeight() + mScaledInsets.bottom,
|
||||
mCornerRadius);
|
||||
} else {
|
||||
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
public float getCornerRadius() {
|
||||
@@ -253,6 +263,9 @@ public class TaskThumbnailView extends View {
|
||||
: getMeasuredWidth() / thumbnailWidth;
|
||||
}
|
||||
|
||||
mScaledInsets.set(thumbnailInsets);
|
||||
Utilities.scaleRect(mScaledInsets, thumbnailScale);
|
||||
|
||||
if (rotate) {
|
||||
int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
|
||||
mMatrix.setRotate(90 * rotationDir);
|
||||
|
||||
@@ -86,7 +86,7 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
/**
|
||||
* How much to scale down pages near the edge of the screen.
|
||||
*/
|
||||
private static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
|
||||
public static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
|
||||
|
||||
public static final long SCALE_ICON_DURATION = 120;
|
||||
private static final long DIM_ANIM_DURATION = 700;
|
||||
@@ -141,6 +141,7 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
private IconView mIconView;
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private boolean mIsFullscreen;
|
||||
|
||||
private Animator mIconAndDimAnimator;
|
||||
private float mFocusTransitionProgress = 1;
|
||||
@@ -508,4 +509,18 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
Log.w(tag, msg);
|
||||
Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the icon and shows insets when this TaskView is about to be shown fullscreen.
|
||||
*/
|
||||
public void setFullscreen(boolean isFullscreen) {
|
||||
mIsFullscreen = isFullscreen;
|
||||
mIconView.setVisibility(mIsFullscreen ? INVISIBLE : VISIBLE);
|
||||
setClipChildren(!mIsFullscreen);
|
||||
setClipToPadding(!mIsFullscreen);
|
||||
}
|
||||
|
||||
public boolean isFullscreen() {
|
||||
return mIsFullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2018 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#############################################
|
||||
# Launcher Robolectric test target. #
|
||||
#############################################
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := LauncherRoboTests
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
androidx.test.runner \
|
||||
androidx.test.rules \
|
||||
mockito-robolectric-prebuilt \
|
||||
truth-prebuilt
|
||||
LOCAL_JAVA_LIBRARIES := \
|
||||
platform-robolectric-3.6.1-prebuilt
|
||||
|
||||
LOCAL_INSTRUMENTATION_FOR := Launcher3
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
|
||||
############################################
|
||||
# Target to run the previous target. #
|
||||
############################################
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := RunLauncherRoboTests
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_JAVA_LIBRARIES := \
|
||||
LauncherRoboTests
|
||||
|
||||
LOCAL_TEST_PACKAGE := Launcher3
|
||||
|
||||
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src \
|
||||
|
||||
LOCAL_ROBOTEST_TIMEOUT := 36000
|
||||
|
||||
include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Robolectric unit tests for {@link IntSet}
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 26)
|
||||
public class IntSetTest {
|
||||
|
||||
@Test
|
||||
public void shouldBeEmptyInitially() {
|
||||
IntSet set = new IntSet();
|
||||
assertThat(set.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oneElementSet() {
|
||||
IntSet set = new IntSet();
|
||||
set.add(2);
|
||||
assertThat(set.size()).isEqualTo(1);
|
||||
assertTrue(set.contains(2));
|
||||
assertFalse(set.contains(1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void twoElementSet() {
|
||||
IntSet set = new IntSet();
|
||||
set.add(2);
|
||||
set.add(1);
|
||||
assertThat(set.size()).isEqualTo(2);
|
||||
assertTrue(set.contains(2));
|
||||
assertTrue(set.contains(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeElementSet() {
|
||||
IntSet set = new IntSet();
|
||||
set.add(2);
|
||||
set.add(1);
|
||||
set.add(10);
|
||||
assertThat(set.size()).isEqualTo(3);
|
||||
assertEquals("1, 2, 10", set.mArray.toConcatString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void duplicateEntries() {
|
||||
IntSet set = new IntSet();
|
||||
set.add(2);
|
||||
set.add(2);
|
||||
assertEquals(1, set.size());
|
||||
}
|
||||
}
|
||||
@@ -625,6 +625,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
mMaxScrollX = computeMaxScrollX();
|
||||
}
|
||||
|
||||
public int getMaxScrollX() {
|
||||
return mMaxScrollX;
|
||||
}
|
||||
|
||||
protected int computeMaxScrollX() {
|
||||
int childCount = getChildCount();
|
||||
if (childCount > 0) {
|
||||
@@ -640,6 +644,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public int getPageSpacing() {
|
||||
return mPageSpacing;
|
||||
}
|
||||
|
||||
private void dispatchPageCountChanged() {
|
||||
if (mPageIndicator != null) {
|
||||
mPageIndicator.setMarkersCount(getChildCount());
|
||||
|
||||
@@ -22,9 +22,6 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -32,6 +29,9 @@ import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
/**
|
||||
* Defines a set of flags used to control various launcher behaviors.
|
||||
*
|
||||
@@ -87,6 +87,9 @@ abstract class BaseFlags {
|
||||
// trying to make them fit the orientation the device is in.
|
||||
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
|
||||
|
||||
public static final TogglableFlag QUICK_SWITCH = new TogglableFlag("QUICK_SWITCH", false,
|
||||
"Swiping right on the nav bar while in an app switches to the previous app");
|
||||
|
||||
/**
|
||||
* Feature flag to handle define config changes dynamically instead of killing the process.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.launcher3.tests">
|
||||
|
||||
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
|
||||
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
import static android.content.pm.PackageManager.DONT_KILL_APP;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
@@ -36,6 +38,7 @@ public class TestCommandReceiver extends ContentProvider {
|
||||
|
||||
public static final String ENABLE_TEST_LAUNCHER = "enable-test-launcher";
|
||||
public static final String DISABLE_TEST_LAUNCHER = "disable-test-launcher";
|
||||
public static final String KILL_PROCESS = "kill-process";
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
@@ -83,14 +86,22 @@ public class TestCommandReceiver extends ContentProvider {
|
||||
COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP);
|
||||
return null;
|
||||
}
|
||||
|
||||
case KILL_PROCESS: {
|
||||
((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)).
|
||||
killBackgroundProcesses(arg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return super.call(method, arg, extras);
|
||||
}
|
||||
|
||||
public static Bundle callCommand(String command) {
|
||||
return callCommand(command, null);
|
||||
}
|
||||
|
||||
public static Bundle callCommand(String command, String arg) {
|
||||
Instrumentation inst = InstrumentationRegistry.getInstrumentation();
|
||||
Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands");
|
||||
return inst.getTargetContext().getContentResolver().call(uri, command, null, null);
|
||||
return inst.getTargetContext().getContentResolver().call(uri, command, arg, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user