Merging ub-launcher3-qt-dev, build 5582981
am: 90eb08d838
Change-Id: I3e277511d94b6a121119c838bb7d3046e42c8d23
This commit is contained in:
@@ -154,13 +154,13 @@
|
||||
|
||||
<!--
|
||||
The content provider for exposing various launcher grid options.
|
||||
TODO: Enable when all apps columns are correct
|
||||
TODO: Add proper permissions
|
||||
-->
|
||||
<provider
|
||||
android:name="com.android.launcher3.graphics.GridOptionsProvider"
|
||||
android:authorities="${packageName}.grid_control"
|
||||
android:enabled="false"
|
||||
android:exported="true" />
|
||||
-->
|
||||
|
||||
<!--
|
||||
The settings activity. To extend point settings_fragment_name to appropriate fragment class
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.launcher3">
|
||||
<uses-sdk android:targetSdkVersion="28" android:minSdkVersion="25"/>
|
||||
<uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
|
||||
<!--
|
||||
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
|
||||
Refer comments around specific entries on how to extend individual components.
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/task_item_height"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:clipChildren="false">
|
||||
<com.android.quickstep.views.TaskThumbnailIconView
|
||||
android:id="@+id/task_icon_and_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
@@ -768,6 +769,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
Rect endRect = new Rect();
|
||||
thumbnailView.getGlobalVisibleRect(endRect);
|
||||
Rect appBounds = appTarget.sourceContainerBounds;
|
||||
RectF currentAppRect = new RectF();
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(this);
|
||||
@@ -810,17 +812,30 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
appMatrix.preScale(mScaleX.value, mScaleY.value,
|
||||
Matrix m = new Matrix();
|
||||
m.preScale(mScaleX.value, mScaleY.value,
|
||||
appBounds.width() / 2.0f, appBounds.height() / 2.0f);
|
||||
appMatrix.postTranslate(mTranslationX.value, mTranslationY.value);
|
||||
|
||||
m.postTranslate(mTranslationX.value, mTranslationY.value);
|
||||
appMatrix.preConcat(m);
|
||||
params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, appMatrix,
|
||||
null /* windowCrop */, getLayer(appTarget, boostedMode),
|
||||
0 /* cornerRadius */);
|
||||
surfaceApplier.scheduleApply(params);
|
||||
|
||||
m.mapRect(currentAppRect, new RectF(appBounds));
|
||||
setViewToRect(thumbnailView, new RectF(endRect), currentAppRect);
|
||||
appMatrix.reset();
|
||||
}
|
||||
});
|
||||
remoteAppAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
thumbnailView.setTranslationY(0);
|
||||
thumbnailView.setTranslationX(0);
|
||||
thumbnailView.setScaleX(1);
|
||||
thumbnailView.setScaleY(1);
|
||||
}
|
||||
});
|
||||
anim.play(remoteAppAnim);
|
||||
}
|
||||
|
||||
@@ -886,6 +901,27 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set view properties so that the view fits to the target rect.
|
||||
*
|
||||
* @param view view to set
|
||||
* @param origRect original rect that view was located
|
||||
* @param targetRect rect to set to
|
||||
*/
|
||||
private void setViewToRect(View view, RectF origRect, RectF targetRect) {
|
||||
float dX = targetRect.left - origRect.left;
|
||||
float dY = targetRect.top - origRect.top;
|
||||
view.setTranslationX(dX);
|
||||
view.setTranslationY(dY);
|
||||
|
||||
float scaleX = targetRect.width() / origRect.width();
|
||||
float scaleY = targetRect.height() / origRect.height();
|
||||
view.setPivotX(0);
|
||||
view.setPivotY(0);
|
||||
view.setScaleX(scaleX);
|
||||
view.setScaleY(scaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets = insets;
|
||||
|
||||
@@ -85,6 +85,13 @@
|
||||
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
||||
tools:node="remove" />
|
||||
|
||||
<activity
|
||||
android:name="com.android.launcher3.proxy.ProxyActivityStarter"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
+2
-2
@@ -19,7 +19,6 @@ package com.android.launcher3.appprediction;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APPS_PREDICTION_TIPS;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.CornerPathEffect;
|
||||
import android.graphics.Paint;
|
||||
@@ -39,6 +38,7 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.FloatingHeaderView;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
@@ -152,7 +152,7 @@ public class AllAppsTipView extends AbstractFloatingView {
|
||||
|| !launcher.isInState(ALL_APPS)
|
||||
|| hasSeenAllAppsTip(launcher)
|
||||
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|
||||
|| ActivityManager.isRunningInTestHarness()) {
|
||||
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -27,11 +27,13 @@ import android.app.prediction.AppTargetId;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
@@ -97,6 +99,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
new AppPredictionContext.Builder(mContext)
|
||||
.setUiSurface(client.id)
|
||||
.setPredictedTargetCount(count)
|
||||
.setExtras(getAppPredictionContextExtras(client))
|
||||
.build());
|
||||
predictor.registerPredictionUpdates(mContext.getMainExecutor(),
|
||||
PredictionUiStateManager.INSTANCE.get(mContext).appPredictorCallback(client));
|
||||
@@ -104,6 +107,15 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
return predictor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to add custom extras.
|
||||
*/
|
||||
@WorkerThread
|
||||
@Nullable
|
||||
public Bundle getAppPredictionContextExtras(Client client){
|
||||
return null;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
|
||||
+4
@@ -42,6 +42,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchCon
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
|
||||
@@ -148,6 +149,9 @@ public abstract class RecentsUiFactory {
|
||||
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
list.add(new OverviewToAllAppsTouchController(launcher));
|
||||
list.add(new LandscapeEdgeSwipeController(launcher));
|
||||
if (mode.hasGestures) {
|
||||
list.add(new TransposedQuickSwitchTouchController(launcher));
|
||||
}
|
||||
} else {
|
||||
list.add(new PortraitStatesTouchController(launcher,
|
||||
mode.hasGestures /* allowDragToOverview */));
|
||||
|
||||
+6
-1
@@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides;
|
||||
import static com.android.launcher3.LauncherState.RECENTS_CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
@@ -64,6 +65,7 @@ public final class RecentsViewStateController extends
|
||||
}
|
||||
}
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state.getVisibleElements(mLauncher));
|
||||
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +97,10 @@ public final class RecentsViewStateController extends
|
||||
builder.addOnFinishRunnable(() -> mRecentsView.setHintVisibility(1f));
|
||||
}
|
||||
|
||||
setAlphas(config.getPropertySetter(builder), toState.getVisibleElements(mLauncher));
|
||||
PropertySetter propertySetter = config.getPropertySetter(builder);
|
||||
setAlphas(propertySetter, toState.getVisibleElements(mLauncher));
|
||||
float fullscreenProgress = toState.getOverviewFullscreenProgress();
|
||||
propertySetter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, fullscreenProgress, LINEAR);
|
||||
}
|
||||
|
||||
private void setAlphas(PropertySetter propertySetter, int visibleElements) {
|
||||
|
||||
+18
-21
@@ -17,14 +17,13 @@ package com.android.launcher3.uioverrides.states;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
/**
|
||||
* State indicating that the Launcher is behind an app
|
||||
@@ -35,7 +34,11 @@ public class BackgroundAppState extends OverviewState {
|
||||
FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
|
||||
|
||||
public BackgroundAppState(int id) {
|
||||
super(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
|
||||
this(id, LauncherLogProto.ContainerType.TASKSWITCHER);
|
||||
}
|
||||
|
||||
protected BackgroundAppState(int id, int logContainer) {
|
||||
super(id, logContainer, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,23 +58,17 @@ public class BackgroundAppState extends OverviewState {
|
||||
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
|
||||
// Initialize the recents view scale to what it would be when starting swipe up
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
recentsView.getTaskSize(sTempRect);
|
||||
int appWidth = launcher.getDragLayer().getWidth();
|
||||
if (recentsView.shouldUseMultiWindowTaskSizeStrategy()) {
|
||||
ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(launcher).getSystemUiProxy();
|
||||
if (sysUiProxy != null) {
|
||||
try {
|
||||
// Try to use the actual non-minimized app width (launcher will be resized to
|
||||
// the non-minimized bounds, which differs from the app width in landscape
|
||||
// multi-window mode
|
||||
appWidth = sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds().width();
|
||||
} catch (RemoteException e) {
|
||||
// Ignore, fall back to just using the drag layer width
|
||||
}
|
||||
}
|
||||
if (recentsView.getTaskViewCount() == 0) {
|
||||
return super.getOverviewScaleAndTranslation(launcher);
|
||||
}
|
||||
float scale = (float) appWidth / sTempRect.width();
|
||||
return new ScaleAndTranslation(scale, 0f, 0f);
|
||||
TaskView dummyTask = recentsView.getTaskViewAt(recentsView.getCurrentPage());
|
||||
return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask)
|
||||
.getScaleAndTranslation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getOverviewFullscreenProgress() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-23
@@ -15,11 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.uioverrides.states;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
@@ -28,23 +25,10 @@ import com.android.quickstep.views.TaskView;
|
||||
* quick switching from launcher; quick switching from an app uses WindowTransformSwipeHelper.
|
||||
* @see com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget#NEW_TASK
|
||||
*/
|
||||
public class QuickSwitchState extends OverviewState {
|
||||
private static final int STATE_FLAGS =
|
||||
FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
|
||||
public class QuickSwitchState extends BackgroundAppState {
|
||||
|
||||
public QuickSwitchState(int id) {
|
||||
super(id, LauncherLogProto.ContainerType.APP, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
if (recentsView.getTaskViewCount() == 0) {
|
||||
return super.getOverviewScaleAndTranslation(launcher);
|
||||
}
|
||||
TaskView dummyTask = recentsView.getTaskViewAt(0);
|
||||
ClipAnimationHelper clipAnimationHelper = new ClipAnimationHelper(launcher);
|
||||
return clipAnimationHelper.getOverviewFullscreenScaleAndTranslation(dummyTask);
|
||||
super(id, LauncherLogProto.ContainerType.APP);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,11 +39,6 @@ public class QuickSwitchState extends OverviewState {
|
||||
return new ScaleAndTranslation(1, 0, translationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVerticalProgress(Launcher launcher) {
|
||||
return BACKGROUND_APP.getVerticalProgress(launcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVisibleElements(Launcher launcher) {
|
||||
return NONE;
|
||||
|
||||
+6
-1
@@ -43,9 +43,11 @@ import com.android.quickstep.views.RecentsView;
|
||||
public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
|
||||
private static final long PEEK_ANIM_DURATION = 100;
|
||||
private static final float MAX_DISPLACEMENT_PERCENT = 0.75f;
|
||||
|
||||
private final MotionPauseDetector mMotionPauseDetector;
|
||||
private final float mMotionPauseMinDisplacement;
|
||||
private final float mMotionPauseMaxDisplacement;
|
||||
|
||||
private AnimatorSet mPeekAnim;
|
||||
|
||||
@@ -53,6 +55,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
super(l, false /* allowDragToOverview */);
|
||||
mMotionPauseDetector = new MotionPauseDetector(l);
|
||||
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
|
||||
mMotionPauseMaxDisplacement = getShiftRange() * MAX_DISPLACEMENT_PERCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,7 +104,9 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement, MotionEvent event) {
|
||||
mMotionPauseDetector.setDisallowPause(-displacement < mMotionPauseMinDisplacement);
|
||||
float upDisplacement = -displacement;
|
||||
mMotionPauseDetector.setDisallowPause(upDisplacement < mMotionPauseMinDisplacement
|
||||
|| upDisplacement > mMotionPauseMaxDisplacement);
|
||||
mMotionPauseDetector.addPosition(displacement, event.getEventTime());
|
||||
return super.onDrag(displacement, event);
|
||||
}
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import android.view.MotionEvent;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.TouchInteractionService;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -52,7 +53,7 @@ public class OverviewToAllAppsTouchController extends PortraitStatesTouchControl
|
||||
// In all-apps only listen if the container cannot scroll itself
|
||||
return mLauncher.getAppsView().shouldContainerScroll(ev);
|
||||
} else if (mLauncher.isInState(NORMAL)) {
|
||||
return true;
|
||||
return (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0;
|
||||
} else if (mLauncher.isInState(OVERVIEW)) {
|
||||
RecentsView rv = mLauncher.getOverviewPanel();
|
||||
return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
|
||||
|
||||
+5
-1
@@ -57,7 +57,11 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
|
||||
private @Nullable TaskView mTaskToLaunch;
|
||||
|
||||
public QuickSwitchTouchController(Launcher launcher) {
|
||||
super(launcher, SwipeDetector.HORIZONTAL);
|
||||
this(launcher, SwipeDetector.HORIZONTAL);
|
||||
}
|
||||
|
||||
protected QuickSwitchTouchController(Launcher l, SwipeDetector.Direction dir) {
|
||||
super(l, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -18,8 +18,8 @@ package com.android.launcher3.uioverrides.touchcontrollers;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
|
||||
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
|
||||
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -231,7 +231,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
} else {
|
||||
mFlingBlockCheck.onEvent();
|
||||
}
|
||||
mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier);
|
||||
mCurrentAnimation.setPlayFraction(Utilities.boundToRange(
|
||||
totalDisplacement * mProgressMultiplier, 0, 1));
|
||||
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsView.getCurrentPage() != 0 || isGoingUp) {
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.uioverrides.touchcontrollers;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
|
||||
public class TransposedQuickSwitchTouchController extends QuickSwitchTouchController {
|
||||
|
||||
public TransposedQuickSwitchTouchController(Launcher launcher) {
|
||||
super(launcher, SwipeDetector.VERTICAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
|
||||
return super.getTargetState(fromState,
|
||||
isDragTowardPositive ^ mLauncher.getDeviceProfile().isSeascape());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float initCurrentAnimation(int animComponents) {
|
||||
float multiplier = super.initCurrentAnimation(animComponents);
|
||||
return mLauncher.getDeviceProfile().isSeascape() ? multiplier : -multiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getShiftRange() {
|
||||
return mLauncher.getDeviceProfile().heightPx / 2f;
|
||||
}
|
||||
}
|
||||
+18
-10
@@ -55,7 +55,6 @@ import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
@@ -118,16 +117,15 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
}
|
||||
final RectF iconLocation = new RectF();
|
||||
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
|
||||
final FloatingIconView floatingView = canUseWorkspaceView
|
||||
? FloatingIconView.getFloatingIconView(activity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, null /* recycle */)
|
||||
FloatingIconView floatingIconView = canUseWorkspaceView
|
||||
? recentsView.getFloatingIconView(activity, workspaceView, iconLocation)
|
||||
: null;
|
||||
|
||||
return new HomeAnimationFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public View getFloatingView() {
|
||||
return floatingView;
|
||||
return floatingIconView;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -186,6 +184,12 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
@Override
|
||||
public void createActivityController(long transitionLength) {
|
||||
createActivityControllerInternal(activity, fromState, transitionLength, callback);
|
||||
// Creating the activity controller animation sometimes reapplies the launcher state
|
||||
// (because we set the animation as the current state animation), so we reapply the
|
||||
// attached state here as well to ensure recents is shown/hidden appropriately.
|
||||
if (SysUINavigationMode.getMode(activity) == Mode.NO_BUTTON) {
|
||||
setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -267,7 +271,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
endState.getVerticalProgress(activity));
|
||||
anim.play(shiftAnim);
|
||||
}
|
||||
playScaleDownAnim(anim, activity, endState);
|
||||
playScaleDownAnim(anim, activity, fromState, endState);
|
||||
|
||||
anim.setDuration(transitionLength * 2);
|
||||
AnimatorPlaybackController controller =
|
||||
@@ -293,7 +297,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
/**
|
||||
* Scale down recents from the center task being full screen to being in overview.
|
||||
*/
|
||||
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher,
|
||||
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState,
|
||||
LauncherState endState) {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
|
||||
@@ -301,19 +305,23 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
return;
|
||||
}
|
||||
|
||||
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
|
||||
LauncherState.ScaleAndTranslation fromScaleAndTranslation
|
||||
= clipHelper.getOverviewFullscreenScaleAndTranslation(v);
|
||||
= fromState.getOverviewScaleAndTranslation(launcher);
|
||||
LauncherState.ScaleAndTranslation endScaleAndTranslation
|
||||
= endState.getOverviewScaleAndTranslation(launcher);
|
||||
float fromFullscreenProgress = fromState.getOverviewFullscreenProgress();
|
||||
float endFullscreenProgress = endState.getOverviewFullscreenProgress();
|
||||
|
||||
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY,
|
||||
fromScaleAndTranslation.scale, endScaleAndTranslation.scale);
|
||||
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
|
||||
fromScaleAndTranslation.translationY, endScaleAndTranslation.translationY);
|
||||
Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView,
|
||||
RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress);
|
||||
scale.setInterpolator(LINEAR);
|
||||
translateY.setInterpolator(LINEAR);
|
||||
anim.playTogether(scale, translateY);
|
||||
applyFullscreenProgress.setInterpolator(LINEAR);
|
||||
anim.playTogether(scale, translateY, applyFullscreenProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.RecentsAnimationListenerSet;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Utility class used to store state information shared across multiple transitions.
|
||||
@@ -134,4 +135,13 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
nextRunningTaskId = -1;
|
||||
goingToLauncher = false;
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter pw) {
|
||||
pw.println(prefix + "goingToLauncher=" + goingToLauncher);
|
||||
pw.println(prefix + "canGestureBeContinued=" + canGestureBeContinued);
|
||||
pw.println(prefix + "recentsAnimationFinishInterrupted=" + recentsAnimationFinishInterrupted);
|
||||
pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId);
|
||||
pw.println(prefix + "lastAnimationCancelled=" + mLastAnimationCancelled);
|
||||
pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
// TODO(b/118266305): Temporarily disable splitscreen for secondary display while new
|
||||
// implementation is enabled
|
||||
return !activity.getDeviceProfile().isMultiWindowMode
|
||||
&& displayId == DEFAULT_DISPLAY;
|
||||
&& (displayId == -1 || displayId == DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+85
-8
@@ -84,8 +84,31 @@ import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper around a list for processing arguments.
|
||||
*/
|
||||
class ArgList extends LinkedList<String> {
|
||||
public ArgList(List<String> l) {
|
||||
super(l);
|
||||
}
|
||||
|
||||
public String peekArg() {
|
||||
return peekFirst();
|
||||
}
|
||||
|
||||
public String nextArg() {
|
||||
return pollFirst().toLowerCase();
|
||||
}
|
||||
|
||||
public String nextArgExact() {
|
||||
return pollFirst();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Service connected by system-UI for handling touch interaction.
|
||||
*/
|
||||
@@ -439,12 +462,18 @@ public class TouchInteractionService extends Service implements
|
||||
mUncheckedConsumer.onMotionEvent(event);
|
||||
}
|
||||
|
||||
private boolean validSystemUiFlags() {
|
||||
return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0;
|
||||
}
|
||||
|
||||
private boolean topTaskLocked() {
|
||||
return ActivityManagerWrapper.getInstance().isLockToAppActive();
|
||||
}
|
||||
|
||||
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
|
||||
boolean validSystemUIFlags = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0;
|
||||
boolean topTaskLocked = ActivityManagerWrapper.getInstance().isLockToAppActive();
|
||||
boolean isInValidSystemUiState = validSystemUIFlags && !topTaskLocked;
|
||||
boolean topTaskLocked = topTaskLocked();
|
||||
boolean isInValidSystemUiState = validSystemUiFlags() && !topTaskLocked;
|
||||
|
||||
if (!mIsUserUnlocked) {
|
||||
if (isInValidSystemUiState) {
|
||||
@@ -476,7 +505,7 @@ public class TouchInteractionService extends Service implements
|
||||
if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
|
||||
base = new AccessibilityInputConsumer(this, mISystemUiProxy,
|
||||
(mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base,
|
||||
mInputMonitorCompat);
|
||||
mInputMonitorCompat, mSwipeTouchRegion);
|
||||
}
|
||||
}
|
||||
return base;
|
||||
@@ -527,7 +556,7 @@ public class TouchInteractionService extends Service implements
|
||||
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
|
||||
mOverviewComponentObserver.getOverviewIntent(), activityControl,
|
||||
shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
|
||||
mSwipeSharedState, mInputMonitorCompat);
|
||||
mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -540,7 +569,55 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
TOUCH_INTERACTION_LOG.dump("", pw);
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
|
||||
if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
|
||||
ArgList args = new ArgList(Arrays.asList(rawArgs));
|
||||
switch (args.nextArg()) {
|
||||
case "cmd":
|
||||
if (args.peekArg() == null) {
|
||||
printAvailableCommands(pw);
|
||||
} else {
|
||||
onCommand(pw, args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Dump everything
|
||||
pw.println("TouchState:");
|
||||
pw.println(" navMode=" + mMode);
|
||||
pw.println(" validSystemUiFlags=" + validSystemUiFlags()
|
||||
+ " flags=" + mSystemUiStateFlags);
|
||||
pw.println(" topTaskLocked=" + topTaskLocked());
|
||||
pw.println(" isDeviceLocked=" + mKM.isDeviceLocked());
|
||||
pw.println(" screenPinned=" +
|
||||
ActivityManagerWrapper.getInstance().isScreenPinningActive());
|
||||
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
||||
pw.println(" a11yClickable="
|
||||
+ ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0));
|
||||
pw.println(" a11yLongClickable="
|
||||
+ ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0));
|
||||
pw.println(" resumed="
|
||||
+ mOverviewComponentObserver.getActivityControlHelper().isResumed());
|
||||
pw.println(" useSharedState=" + mConsumer.useSharedSwipeState());
|
||||
if (mConsumer.useSharedSwipeState()) {
|
||||
mSwipeSharedState.dump(" ", pw);
|
||||
}
|
||||
pw.println(" mConsumer=" + mConsumer.getName());
|
||||
TOUCH_INTERACTION_LOG.dump("", pw);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void printAvailableCommands(PrintWriter pw) {
|
||||
pw.println("Available commands:");
|
||||
pw.println(" clear-touch-log: Clears the touch interaction log");
|
||||
}
|
||||
|
||||
private void onCommand(PrintWriter pw, ArgList args) {
|
||||
switch (args.nextArg()) {
|
||||
case "clear-touch-log":
|
||||
TOUCH_INTERACTION_LOG.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-16
@@ -175,7 +175,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
|
||||
| STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
|
||||
|
||||
NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP, true),
|
||||
NEW_TASK(0, STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT, false, true,
|
||||
ContainerType.APP, true),
|
||||
|
||||
LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP, false);
|
||||
|
||||
@@ -319,7 +320,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
mStateCallback.addCallback(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
|
||||
this::resumeLastTask);
|
||||
mStateCallback.addCallback(STATE_START_NEW_TASK | STATE_APP_CONTROLLER_RECEIVED,
|
||||
mStateCallback.addCallback(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED,
|
||||
this::startNewTask);
|
||||
|
||||
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
|
||||
@@ -503,6 +504,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
private void setupRecentsViewUi() {
|
||||
if (mContinuingLastGesture) {
|
||||
updateSysUiFlags(mCurrentShift.value);
|
||||
return;
|
||||
}
|
||||
mRecentsView.onGestureAnimationStart(mRunningTaskId);
|
||||
@@ -676,15 +678,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
}
|
||||
// Update insets of the non-running tasks, as we might switch to them.
|
||||
int runningTaskIndex = mRecentsView == null ? -1 : mRecentsView.getRunningTaskIndex();
|
||||
if (runningTaskIndex >= 0) {
|
||||
for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) {
|
||||
if (i != runningTaskIndex || !mRecentsAnimationWrapper.hasTargets()) {
|
||||
mRecentsView.getTaskViewAt(i).setFullscreenProgress(1 - mCurrentShift.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mLauncherTransitionController == null || mLauncherTransitionController
|
||||
.getAnimationPlayer().isStarted()) {
|
||||
@@ -705,12 +698,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
private void updateSysUiFlags(float windowProgress) {
|
||||
if (mRecentsView != null) {
|
||||
TaskView centermostTask = mRecentsView.getTaskViewAt(mRecentsView
|
||||
.getPageNearestToCenterOfScreen());
|
||||
int centermostTaskFlags = centermostTask == null ? 0
|
||||
: centermostTask.getThumbnail().getSysUiStatusNavFlags();
|
||||
boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
// We will handle the sysui flags based on the centermost task view.
|
||||
mRecentsAnimationWrapper.setWindowThresholdCrossed(true);
|
||||
int sysuiFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD
|
||||
? 0
|
||||
: mRecentsView.getTaskViewAt(mRecentsView.getPageNearestToCenterOfScreen())
|
||||
.getThumbnail().getSysUiStatusNavFlags();
|
||||
mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0
|
||||
|| useHomeScreenFlags);
|
||||
int sysuiFlags = useHomeScreenFlags ? 0 : centermostTaskFlags;
|
||||
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.RectF;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
@@ -46,6 +47,7 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer {
|
||||
private final VelocityTracker mVelocityTracker;
|
||||
private final MotionPauseDetector mMotionPauseDetector;
|
||||
private final boolean mAllowLongClick;
|
||||
private final RectF mSwipeTouchRegion;
|
||||
|
||||
private final float mMinGestureDistance;
|
||||
private final float mMinFlingVelocity;
|
||||
@@ -55,13 +57,15 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer {
|
||||
private float mTotalY;
|
||||
|
||||
public AccessibilityInputConsumer(Context context, ISystemUiProxy systemUiProxy,
|
||||
boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor) {
|
||||
boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor,
|
||||
RectF swipeTouchRegion) {
|
||||
super(delegate, inputMonitor);
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mMinGestureDistance = context.getResources()
|
||||
.getDimension(R.dimen.accessibility_gesture_min_swipe_distance);
|
||||
mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
|
||||
mSwipeTouchRegion = swipeTouchRegion;
|
||||
|
||||
mMotionPauseDetector = new MotionPauseDetector(context);
|
||||
mAllowLongClick = allowLongClick;
|
||||
@@ -98,10 +102,11 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer {
|
||||
}
|
||||
case ACTION_POINTER_DOWN: {
|
||||
if (mState == STATE_INACTIVE) {
|
||||
if (mDelegate.allowInterceptByParent()) {
|
||||
int pointerIndex = ev.getActionIndex();
|
||||
if (mSwipeTouchRegion.contains(ev.getX(pointerIndex), ev.getY(pointerIndex))
|
||||
&& mDelegate.allowInterceptByParent()) {
|
||||
setActive(ev);
|
||||
|
||||
int pointerIndex = ev.getActionIndex();
|
||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||
mDownY = ev.getY(pointerIndex);
|
||||
} else {
|
||||
|
||||
+10
-1
@@ -19,8 +19,10 @@ package com.android.quickstep.inputconsumers;
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.FLING;
|
||||
@@ -38,6 +40,7 @@ import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -117,6 +120,12 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
mTimeFraction = 0;
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_DOWN: {
|
||||
if (mState != STATE_ACTIVE) {
|
||||
mState = STATE_DELEGATE_ACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ACTION_POINTER_UP: {
|
||||
int ptrIdx = ev.getActionIndex();
|
||||
int ptrId = ev.getPointerId(ptrIdx);
|
||||
@@ -257,7 +266,7 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
if (fling) {
|
||||
if (fling && !mLaunchedAssistant) {
|
||||
mLastProgress = 1;
|
||||
updateAssistant(FLING);
|
||||
}
|
||||
|
||||
+19
@@ -63,4 +63,23 @@ public interface InputConsumer {
|
||||
onKeyEvent((KeyEvent) ev);
|
||||
}
|
||||
}
|
||||
|
||||
default String getName() {
|
||||
switch (getType()) {
|
||||
case TYPE_OVERVIEW:
|
||||
return "OVERVIEW";
|
||||
case TYPE_OTHER_ACTIVITY:
|
||||
return "OTHER_ACTIVITY";
|
||||
case TYPE_ASSISTANT:
|
||||
return "ASSISTANT";
|
||||
case TYPE_DEVICE_LOCKED:
|
||||
return "DEVICE_LOCKED";
|
||||
case TYPE_ACCESSIBILITY:
|
||||
return "ACCESSIBILITY";
|
||||
case TYPE_SCREEN_PINNED:
|
||||
return "SCREEN_PINNED";
|
||||
default:
|
||||
return "NO_OP";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-6
@@ -18,6 +18,7 @@ package com.android.quickstep.inputconsumers;
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
import static android.view.MotionEvent.INVALID_POINTER_ID;
|
||||
@@ -36,6 +37,7 @@ import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -90,6 +92,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
private final SwipeSharedState mSwipeSharedState;
|
||||
private final InputMonitorCompat mInputMonitorCompat;
|
||||
private final SysUINavigationMode.Mode mMode;
|
||||
private final RectF mSwipeTouchRegion;
|
||||
|
||||
private final int mDisplayRotation;
|
||||
|
||||
@@ -127,7 +130,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks,
|
||||
InputConsumerController inputConsumer,
|
||||
Consumer<OtherActivityInputConsumer> onCompleteCallback,
|
||||
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat) {
|
||||
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
|
||||
RectF swipeTouchRegion) {
|
||||
super(base);
|
||||
|
||||
mMainThreadHandler = new Handler(Looper.getMainLooper());
|
||||
@@ -135,6 +139,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
mRecentsModel = recentsModel;
|
||||
mHomeIntent = homeIntent;
|
||||
mMode = SysUINavigationMode.getMode(base);
|
||||
mSwipeTouchRegion = swipeTouchRegion;
|
||||
|
||||
mMotionPauseDetector = new MotionPauseDetector(base);
|
||||
mMotionPauseMinDisplacement = base.getResources().getDimension(
|
||||
@@ -204,6 +209,19 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
RaceConditionTracker.onEvent(DOWN_EVT, EXIT);
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_DOWN: {
|
||||
if (!mPassedTouchSlop) {
|
||||
// Cancel interaction in case of multi-touch interaction
|
||||
int ptrIdx = ev.getActionIndex();
|
||||
if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
|
||||
int action = ev.getAction();
|
||||
ev.setAction(ACTION_CANCEL);
|
||||
finishTouchTracking(ev);
|
||||
ev.setAction(action);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_POINTER_UP: {
|
||||
int ptrIdx = ev.getActionIndex();
|
||||
int ptrId = ev.getPointerId(ptrIdx);
|
||||
@@ -273,13 +291,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
break;
|
||||
}
|
||||
case ACTION_CANCEL:
|
||||
// TODO: Should be different than ACTION_UP
|
||||
case ACTION_UP: {
|
||||
RaceConditionTracker.onEvent(UP_EVT, ENTER);
|
||||
TraceHelper.endSection("TouchInt");
|
||||
|
||||
finishTouchTracking(ev);
|
||||
RaceConditionTracker.onEvent(UP_EVT, EXIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -342,6 +355,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
* the animation can still be running.
|
||||
*/
|
||||
private void finishTouchTracking(MotionEvent ev) {
|
||||
RaceConditionTracker.onEvent(UP_EVT, ENTER);
|
||||
TraceHelper.endSection("TouchInt");
|
||||
|
||||
if (mPassedDragSlop && mInteractionHandler != null) {
|
||||
if (ev.getActionMasked() == ACTION_CANCEL) {
|
||||
mInteractionHandler.onGestureCancelled();
|
||||
@@ -374,6 +390,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
mMotionPauseDetector.clear();
|
||||
RaceConditionTracker.onEvent(UP_EVT, EXIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-26
@@ -285,13 +285,20 @@ public class ClipAnimationHelper {
|
||||
/**
|
||||
* Compute scale and translation y such that the specified task view fills the screen.
|
||||
*/
|
||||
public LauncherState.ScaleAndTranslation getOverviewFullscreenScaleAndTranslation(TaskView v) {
|
||||
public ClipAnimationHelper updateForFullscreenOverview(TaskView v) {
|
||||
TaskThumbnailView thumbnailView = v.getThumbnail();
|
||||
RecentsView recentsView = v.getRecentsView();
|
||||
fromTaskThumbnailView(thumbnailView, recentsView);
|
||||
Rect taskSize = new Rect();
|
||||
recentsView.getTaskSize(taskSize);
|
||||
updateTargetRect(taskSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The source rect's scale and translation relative to the target rect.
|
||||
*/
|
||||
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
|
||||
float scale = mSourceRect.width() / mTargetRect.width();
|
||||
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
|
||||
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
|
||||
@@ -332,35 +339,10 @@ public class ClipAnimationHelper {
|
||||
mSourceStackBounds.offset(left, insets.top + fullDp.availableHeightPx - taskHeight);
|
||||
}
|
||||
|
||||
public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
|
||||
RectF currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
|
||||
canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
|
||||
mSourceStackBounds.top - mHomeStackBounds.top);
|
||||
mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL);
|
||||
|
||||
canvas.concat(mTmpMatrix);
|
||||
canvas.translate(mTargetRect.left, mTargetRect.top);
|
||||
|
||||
float scale = mTargetRect.width() / mSourceRect.width();
|
||||
float insetProgress = (1 - progress);
|
||||
float windowCornerRadius = mUseRoundedCornersOnWindows
|
||||
? mWindowCornerRadius : 0;
|
||||
ttv.drawOnCanvas(canvas,
|
||||
-mSourceWindowClipInsets.left * insetProgress,
|
||||
-mSourceWindowClipInsets.top * insetProgress,
|
||||
ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
|
||||
ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
|
||||
Utilities.mapRange(progress, windowCornerRadius * scale, ttv.getCornerRadius()));
|
||||
}
|
||||
|
||||
public RectF getTargetRect() {
|
||||
return mTargetRect;
|
||||
}
|
||||
|
||||
public RectF getSourceRect() {
|
||||
return mSourceRect;
|
||||
}
|
||||
|
||||
public float getCurrentCornerRadius() {
|
||||
return mCurrentCornerRadius;
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
public class TaskViewDrawable extends Drawable {
|
||||
|
||||
public static final FloatProperty<TaskViewDrawable> PROGRESS =
|
||||
new FloatProperty<TaskViewDrawable>("progress") {
|
||||
@Override
|
||||
public void setValue(TaskViewDrawable taskViewDrawable, float v) {
|
||||
taskViewDrawable.setProgress(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskViewDrawable taskViewDrawable) {
|
||||
return taskViewDrawable.mProgress;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The progress at which we play the atomic icon scale animation.
|
||||
*/
|
||||
private static final float ICON_SCALE_THRESHOLD = 0.95f;
|
||||
|
||||
private final RecentsView mParent;
|
||||
private final View mIconView;
|
||||
private final float[] mIconPos;
|
||||
private final TaskView mTaskView;
|
||||
|
||||
private final TaskThumbnailView mThumbnailView;
|
||||
|
||||
private final ClipAnimationHelper mClipAnimationHelper;
|
||||
|
||||
private float mProgress = 1;
|
||||
private boolean mPassedIconScaleThreshold;
|
||||
private ValueAnimator mIconScaleAnimator;
|
||||
private float mIconScale;
|
||||
|
||||
public TaskViewDrawable(TaskView tv, RecentsView parent) {
|
||||
mParent = parent;
|
||||
mTaskView = tv;
|
||||
mIconView = tv.getIconView();
|
||||
mIconPos = new float[2];
|
||||
mIconScale = mIconView.getScaleX();
|
||||
Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
|
||||
|
||||
mThumbnailView = tv.getThumbnail();
|
||||
mClipAnimationHelper = new ClipAnimationHelper(parent.getContext());
|
||||
mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
|
||||
mClipAnimationHelper.prepareAnimation(
|
||||
BaseActivity.fromContext(tv.getContext()).getDeviceProfile(), true /* isOpening */);
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
mProgress = progress;
|
||||
mParent.invalidate();
|
||||
boolean passedIconScaleThreshold = progress <= ICON_SCALE_THRESHOLD;
|
||||
if (mPassedIconScaleThreshold != passedIconScaleThreshold) {
|
||||
mPassedIconScaleThreshold = passedIconScaleThreshold;
|
||||
animateIconScale(mPassedIconScaleThreshold ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateIconScale(float toScale) {
|
||||
if (mIconScaleAnimator != null) {
|
||||
mIconScaleAnimator.cancel();
|
||||
}
|
||||
mIconScaleAnimator = ValueAnimator.ofFloat(mIconScale, toScale);
|
||||
mIconScaleAnimator.addUpdateListener(valueAnimator -> {
|
||||
mIconScale = (float) valueAnimator.getAnimatedValue();
|
||||
if (mProgress > ICON_SCALE_THRESHOLD) {
|
||||
// Speed up the icon scale to ensure it is 1 when progress is 1.
|
||||
float iconProgress = (mProgress - ICON_SCALE_THRESHOLD) / (1 - ICON_SCALE_THRESHOLD);
|
||||
if (iconProgress > mIconScale) {
|
||||
mIconScale = iconProgress;
|
||||
}
|
||||
}
|
||||
invalidateSelf();
|
||||
});
|
||||
mIconScaleAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIconScaleAnimator = null;
|
||||
}
|
||||
});
|
||||
mIconScaleAnimator.setDuration(TaskView.SCALE_ICON_DURATION);
|
||||
mIconScaleAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.save();
|
||||
canvas.translate(mParent.getScrollX(), mParent.getScrollY());
|
||||
mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress);
|
||||
canvas.restore();
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(mIconPos[0], mIconPos[1]);
|
||||
canvas.scale(mIconScale, mIconScale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
|
||||
mIconView.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
public ClipAnimationHelper getClipAnimationHelper() {
|
||||
return mClipAnimationHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
public TaskView getTaskView() {
|
||||
return mTaskView;
|
||||
}
|
||||
}
|
||||
+16
@@ -30,6 +30,7 @@ import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
@@ -178,6 +179,21 @@ public class LauncherRecentsView extends RecentsView<Launcher> {
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsAnimationWrapper.targetSet != null && tv.isRunningTask()) {
|
||||
mTransformParams.setProgress(1 - progress)
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier)
|
||||
.setForLiveTile(true);
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
|
||||
mTransformParams);
|
||||
} else {
|
||||
redrawLiveTile(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
|
||||
boolean shouldRemoveTask, long duration) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep.views;
|
||||
|
||||
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
@@ -30,7 +31,6 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
import static com.android.quickstep.util.ClipAnimationHelper.TransformParams;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
@@ -75,7 +75,9 @@ import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -91,13 +93,13 @@ import com.android.launcher3.util.OverScroller;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.RecentsAnimationWrapper;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.TaskViewDrawable;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -140,6 +142,19 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> FULLSCREEN_PROGRESS =
|
||||
new FloatProperty<RecentsView>("fullscreenProgress") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setFullscreenProgress(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(RecentsView recentsView) {
|
||||
return recentsView.mFullscreenProgress;
|
||||
}
|
||||
};
|
||||
|
||||
protected RecentsAnimationWrapper mRecentsAnimationWrapper;
|
||||
protected ClipAnimationHelper mClipAnimationHelper;
|
||||
protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
|
||||
@@ -163,6 +178,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private final ClearAllButton mClearAllButton;
|
||||
private final Rect mClearAllButtonDeadZoneRect = new Rect();
|
||||
private final Rect mTaskViewDeadZoneRect = new Rect();
|
||||
protected final ClipAnimationHelper mTempClipAnimationHelper;
|
||||
|
||||
private final ScrollState mScrollState = new ScrollState();
|
||||
// Keeps track of the previously known visible tasks for purposes of loading/unloading task data
|
||||
@@ -274,6 +290,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private float mContentAlpha = 1;
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private float mFullscreenProgress = 0;
|
||||
|
||||
// Keeps track of task id whose visual state should not be reset
|
||||
private int mIgnoreResetTaskId = -1;
|
||||
@@ -288,6 +306,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private Layout mEmptyTextLayout;
|
||||
private LiveTileOverlay mLiveTileOverlay;
|
||||
|
||||
private FloatingIconView mFloatingIconView;
|
||||
|
||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||
(inMultiWindowMode) -> {
|
||||
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
||||
@@ -306,6 +326,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mActivity = (T) BaseActivity.fromContext(context);
|
||||
mModel = RecentsModel.INSTANCE.get(context);
|
||||
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
|
||||
mTempClipAnimationHelper = new ClipAnimationHelper(context);
|
||||
|
||||
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
|
||||
.inflate(R.layout.overview_clear_all_button, this, false);
|
||||
@@ -594,6 +615,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
loadVisibleTaskData();
|
||||
}
|
||||
|
||||
public void setFullscreenProgress(float fullscreenProgress) {
|
||||
mFullscreenProgress = fullscreenProgress;
|
||||
int taskCount = getTaskViewCount();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTaskStackListenerState() {
|
||||
boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
|
||||
&& getWindowVisibility() == VISIBLE;
|
||||
@@ -1282,15 +1311,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
setVisibility(alpha > 0 ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
private float[] getAdjacentScaleAndTranslation(TaskView currTask,
|
||||
float currTaskToScale, float currTaskToTranslationY) {
|
||||
float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale());
|
||||
sTempFloatArray[0] = currTaskToScale;
|
||||
sTempFloatArray[1] = mIsRtl ? -displacement : displacement;
|
||||
sTempFloatArray[2] = currTaskToTranslationY;
|
||||
return sTempFloatArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAdded(View child) {
|
||||
super.onViewAdded(child);
|
||||
@@ -1419,27 +1439,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
int centerTaskIndex = getCurrentPage();
|
||||
boolean launchingCenterTask = taskIndex == centerTaskIndex;
|
||||
|
||||
float toScale = clipAnimationHelper.getSourceRect().width()
|
||||
/ clipAnimationHelper.getTargetRect().width();
|
||||
float toTranslationY = clipAnimationHelper.getSourceRect().centerY()
|
||||
- clipAnimationHelper.getTargetRect().centerY();
|
||||
LauncherState.ScaleAndTranslation toScaleAndTranslation = clipAnimationHelper
|
||||
.getScaleAndTranslation();
|
||||
float toScale = toScaleAndTranslation.scale;
|
||||
float toTranslationY = toScaleAndTranslation.translationY;
|
||||
if (launchingCenterTask) {
|
||||
TaskView centerTask = getTaskViewAt(centerTaskIndex);
|
||||
if (taskIndex - 1 >= 0) {
|
||||
TaskView adjacentTask = getTaskViewAt(taskIndex - 1);
|
||||
float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
|
||||
toScale, toTranslationY);
|
||||
scaleAndTranslation[1] = -scaleAndTranslation[1];
|
||||
anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
|
||||
anim.play(ObjectAnimator.ofFloat(adjacentTask, TaskView.FULLSCREEN_PROGRESS, 1));
|
||||
}
|
||||
if (taskIndex + 1 < getTaskViewCount()) {
|
||||
TaskView adjacentTask = getTaskViewAt(taskIndex + 1);
|
||||
float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
|
||||
toScale, toTranslationY);
|
||||
anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
|
||||
anim.play(ObjectAnimator.ofFloat(adjacentTask, TaskView.FULLSCREEN_PROGRESS, 1));
|
||||
}
|
||||
RecentsView recentsView = tv.getRecentsView();
|
||||
anim.play(ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, toScale));
|
||||
anim.play(ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y, toTranslationY));
|
||||
anim.play(ObjectAnimator.ofFloat(recentsView, FULLSCREEN_PROGRESS, 1));
|
||||
} else {
|
||||
// We are launching an adjacent task, so parallax the center and other adjacent task.
|
||||
float displacementX = tv.getWidth() * (toScale - tv.getCurveScale());
|
||||
@@ -1457,16 +1465,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return anim;
|
||||
}
|
||||
|
||||
private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
|
||||
anim.play(new PropertyListBuilder()
|
||||
.translationX(toScaleAndTranslation[1])
|
||||
.translationY(toScaleAndTranslation[2])
|
||||
.build(child));
|
||||
return anim;
|
||||
}
|
||||
|
||||
public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
|
||||
throw new IllegalStateException("Another pending animation is still running");
|
||||
@@ -1477,60 +1475,38 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return new PendingAnimation(new AnimatorSet());
|
||||
}
|
||||
|
||||
tv.setVisibility(INVISIBLE);
|
||||
int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
|
||||
TaskViewDrawable drawable = new TaskViewDrawable(tv, this);
|
||||
getOverlay().add(drawable);
|
||||
|
||||
final boolean[] passedOverviewThreshold = new boolean[] {false};
|
||||
ObjectAnimator drawableAnim =
|
||||
ObjectAnimator.ofFloat(drawable, TaskViewDrawable.PROGRESS, 1, 0);
|
||||
drawableAnim.setInterpolator(LINEAR);
|
||||
drawableAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
TransformParams mParams = new TransformParams();
|
||||
ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
|
||||
progressAnim.setInterpolator(LINEAR);
|
||||
progressAnim.addUpdateListener(animator -> {
|
||||
// Once we pass a certain threshold, update the sysui flags to match the target
|
||||
// tasks' flags
|
||||
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW,
|
||||
animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD
|
||||
? targetSysUiFlags
|
||||
: 0);
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animator) {
|
||||
// Once we pass a certain threshold, update the sysui flags to match the target
|
||||
// tasks' flags
|
||||
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW,
|
||||
animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD
|
||||
? targetSysUiFlags
|
||||
: 0);
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsAnimationWrapper.targetSet != null
|
||||
&& drawable.getTaskView().isRunningTask()) {
|
||||
mParams.setProgress(1 - animator.getAnimatedFraction())
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier)
|
||||
.setForLiveTile(true);
|
||||
drawable.getClipAnimationHelper().applyTransform(
|
||||
mRecentsAnimationWrapper.targetSet, mParams);
|
||||
} else {
|
||||
redrawLiveTile(true);
|
||||
}
|
||||
}
|
||||
onTaskLaunchAnimationUpdate(animator.getAnimatedFraction(), tv);
|
||||
|
||||
// Passing the threshold from taskview to fullscreen app will vibrate
|
||||
final boolean passed = animator.getAnimatedFraction() >=
|
||||
SUCCESS_TRANSITION_PROGRESS;
|
||||
if (passed != passedOverviewThreshold[0]) {
|
||||
passedOverviewThreshold[0] = passed;
|
||||
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
// Passing the threshold from taskview to fullscreen app will vibrate
|
||||
final boolean passed = animator.getAnimatedFraction() >=
|
||||
SUCCESS_TRANSITION_PROGRESS;
|
||||
if (passed != passedOverviewThreshold[0]) {
|
||||
passedOverviewThreshold[0] = passed;
|
||||
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
});
|
||||
|
||||
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv,
|
||||
drawable.getClipAnimationHelper());
|
||||
anim.play(drawableAnim);
|
||||
ClipAnimationHelper clipAnimationHelper = new ClipAnimationHelper(mActivity);
|
||||
clipAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this);
|
||||
clipAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
|
||||
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, clipAnimationHelper);
|
||||
anim.play(progressAnim);
|
||||
anim.setDuration(duration);
|
||||
|
||||
Consumer<Boolean> onTaskLaunchFinish = (result) -> {
|
||||
onTaskLaunched(result);
|
||||
tv.setVisibility(VISIBLE);
|
||||
getOverlay().remove(drawable);
|
||||
};
|
||||
Consumer<Boolean> onTaskLaunchFinish = this::onTaskLaunched;
|
||||
|
||||
mPendingAnimation = new PendingAnimation(anim);
|
||||
mPendingAnimation.addEndListener((onEndListener) -> {
|
||||
@@ -1556,6 +1532,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return mPendingAnimation;
|
||||
}
|
||||
|
||||
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
|
||||
}
|
||||
|
||||
public abstract boolean shouldUseMultiWindowTaskSizeStrategy();
|
||||
|
||||
protected void onTaskLaunched(boolean success) {
|
||||
@@ -1704,4 +1683,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return super::onTouchEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public FloatingIconView getFloatingIconView(Launcher launcher, View view, RectF iconLocation) {
|
||||
mFloatingIconView = FloatingIconView.getFloatingIconView(launcher, view,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, mFloatingIconView);
|
||||
return mFloatingIconView;
|
||||
}
|
||||
|
||||
public ClipAnimationHelper getTempClipAnimationHelper() {
|
||||
return mTempClipAnimationHelper;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -75,8 +75,6 @@ public class TaskThumbnailView extends View {
|
||||
}
|
||||
};
|
||||
|
||||
private final float mCornerRadius;
|
||||
|
||||
private final BaseActivity mActivity;
|
||||
private final TaskOverlay mOverlay;
|
||||
private final boolean mIsDarkTextTheme;
|
||||
@@ -110,7 +108,6 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mCornerRadius = TaskCornerRadius.get(context);
|
||||
mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
|
||||
mPaint.setFilterBitmap(true);
|
||||
mBackgroundPaint.setColor(Color.WHITE);
|
||||
@@ -118,7 +115,7 @@ public class TaskThumbnailView extends View {
|
||||
mDimmingPaintAfterClearing.setColor(Color.BLACK);
|
||||
mActivity = BaseActivity.fromContext(context);
|
||||
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
|
||||
mFullscreenParams = new TaskView.FullscreenDrawParams(mCornerRadius);
|
||||
mFullscreenParams = new TaskView.FullscreenDrawParams(TaskCornerRadius.get(context));
|
||||
}
|
||||
|
||||
public void bind(Task task) {
|
||||
@@ -225,10 +222,6 @@ public class TaskThumbnailView extends View {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getCornerRadius() {
|
||||
return mCornerRadius;
|
||||
}
|
||||
|
||||
public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height,
|
||||
float cornerRadius) {
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
|
||||
@@ -103,19 +103,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
|
||||
public static final Property<TaskView, Float> ZOOM_SCALE =
|
||||
new FloatProperty<TaskView>("zoomScale") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
taskView.setZoomScale(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mZoomScale;
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<TaskView> FULLSCREEN_PROGRESS =
|
||||
new FloatProperty<TaskView>("fullscreenProgress") {
|
||||
@Override
|
||||
@@ -165,7 +152,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private IconView mIconView;
|
||||
private DigitalWellBeingToast mDigitalWellBeingToast;
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private float mFullscreenProgress;
|
||||
private final FullscreenDrawParams mCurrentFullscreenParams;
|
||||
private final float mCornerRadius;
|
||||
@@ -459,7 +445,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
|
||||
private void resetViewTransforms() {
|
||||
setCurveScale(1);
|
||||
setZoomScale(1);
|
||||
setTranslationX(0f);
|
||||
setTranslationY(0f);
|
||||
setTranslationZ(0);
|
||||
@@ -475,7 +460,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
@Override
|
||||
public void onRecycle() {
|
||||
resetViewTransforms();
|
||||
setFullscreenProgress(0);
|
||||
// Clear any references to the thumbnail (it will be re-read either from the cache or the
|
||||
// system on next bind)
|
||||
mSnapshotView.setThumbnail(mTask, null);
|
||||
if (mTask != null) {
|
||||
mTask.thumbnail = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -522,13 +512,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
return mCurveScale;
|
||||
}
|
||||
|
||||
public void setZoomScale(float adjacentScale) {
|
||||
mZoomScale = adjacentScale;
|
||||
onScaleChanged();
|
||||
}
|
||||
|
||||
private void onScaleChanged() {
|
||||
float scale = mCurveScale * mZoomScale;
|
||||
float scale = mCurveScale;
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
}
|
||||
|
||||
@@ -35,40 +35,42 @@
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.android.quickstep.views.DigitalWellBeingToast
|
||||
android:id="@+id/digital_well_being_toast"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:importantForAccessibility="noHideDescendants"
|
||||
android:background="@drawable/bg_wellbeing_toast"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:id="@+id/digital_well_being_hourglass"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/ic_hourglass_top"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/digital_well_being_remaining_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/white"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
</com.android.quickstep.views.DigitalWellBeingToast>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/proactive_suggest_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:translationY="20dp"
|
||||
android:elevation="4dp"
|
||||
/>
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|center_horizontal">
|
||||
<FrameLayout
|
||||
android:id="@+id/proactive_suggest_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<com.android.quickstep.views.DigitalWellBeingToast
|
||||
android:id="@+id/digital_well_being_toast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:importantForAccessibility="noHideDescendants"
|
||||
android:background="@drawable/bg_wellbeing_toast"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:id="@+id/digital_well_being_hourglass"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/ic_hourglass_top"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/digital_well_being_remaining_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/white"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
</com.android.quickstep.views.DigitalWellBeingToast>
|
||||
</LinearLayout>
|
||||
</com.android.quickstep.views.TaskView>
|
||||
@@ -476,6 +476,16 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
|
||||
float shapeRevealDuration = APP_LAUNCH_DURATION * SHAPE_PROGRESS_DURATION;
|
||||
|
||||
final float startCrop;
|
||||
final float endCrop;
|
||||
if (mDeviceProfile.isVerticalBarLayout()) {
|
||||
startCrop = windowTargetBounds.height();
|
||||
endCrop = windowTargetBounds.width();
|
||||
} else {
|
||||
startCrop = windowTargetBounds.width();
|
||||
endCrop = windowTargetBounds.height();
|
||||
}
|
||||
|
||||
final float windowRadius = mDeviceProfile.isMultiWindowMode
|
||||
? 0 : getWindowCornerRadius(mLauncher.getResources());
|
||||
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
@@ -485,10 +495,10 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
EXAGGERATED_EASE);
|
||||
FloatProp mIconAlpha = new FloatProp(1f, 0f, APP_LAUNCH_ALPHA_START_DELAY,
|
||||
alphaDuration, LINEAR);
|
||||
FloatProp mCropHeight = new FloatProp(windowTargetBounds.width(),
|
||||
windowTargetBounds.height(), 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
|
||||
FloatProp mWindowRadius = new FloatProp(windowTargetBounds.width() / 2f,
|
||||
windowRadius, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
|
||||
FloatProp mCroppedSize = new FloatProp(startCrop, endCrop, 0, APP_LAUNCH_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
FloatProp mWindowRadius = new FloatProp(startCrop / 2f, windowRadius, 0,
|
||||
APP_LAUNCH_DURATION, EXAGGERATED_EASE);
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
@@ -496,10 +506,16 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
float iconWidth = bounds.width() * mIconScale.value;
|
||||
float iconHeight = bounds.height() * mIconScale.value;
|
||||
|
||||
// Animate the window crop so that it starts off as a square, and then reveals
|
||||
// horizontally.
|
||||
int windowWidth = windowTargetBounds.width();
|
||||
int windowHeight = (int) mCropHeight.value;
|
||||
// Animate the window crop so that it starts off as a square.
|
||||
final int windowWidth;
|
||||
final int windowHeight;
|
||||
if (mDeviceProfile.isVerticalBarLayout()) {
|
||||
windowWidth = (int) mCroppedSize.value;
|
||||
windowHeight = windowTargetBounds.height();
|
||||
} else {
|
||||
windowWidth = windowTargetBounds.width();
|
||||
windowHeight = (int) mCroppedSize.value;
|
||||
}
|
||||
crop.set(0, 0, windowWidth, windowHeight);
|
||||
|
||||
// Scale the app window to match the icon size.
|
||||
@@ -522,6 +538,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
float transY0 = temp.top - offsetY;
|
||||
|
||||
float croppedHeight = (windowTargetBounds.height() - crop.height()) * scale;
|
||||
float croppedWidth = (windowTargetBounds.width() - crop.width()) * scale;
|
||||
SurfaceParams[] params = new SurfaceParams[targets.length];
|
||||
for (int i = targets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = targets[i];
|
||||
@@ -535,7 +552,11 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
alpha = 1f - mIconAlpha.value;
|
||||
cornerRadius = mWindowRadius.value;
|
||||
matrix.mapRect(currentBounds, targetBounds);
|
||||
currentBounds.bottom -= croppedHeight;
|
||||
if (mDeviceProfile.isVerticalBarLayout()) {
|
||||
currentBounds.right -= croppedWidth;
|
||||
} else {
|
||||
currentBounds.bottom -= croppedHeight;
|
||||
}
|
||||
mFloatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
|
||||
cornerRadius * scale, true /* isOpening */);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.proxy;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class ProxyActivityStarter extends Activity {
|
||||
|
||||
private static final String TAG = "ProxyActivityStarter";
|
||||
|
||||
public static final String EXTRA_PARAMS = "start-activity-params";
|
||||
|
||||
private StartActivityParams mParams;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setVisible(false);
|
||||
|
||||
mParams = getIntent().getParcelableExtra(EXTRA_PARAMS);
|
||||
if (mParams == null) {
|
||||
Log.d(TAG, "Proxy activity started without params");
|
||||
finishAndRemoveTask();
|
||||
return;
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
// Already started the activity. Just wait for the result.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mParams.intent != null) {
|
||||
startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
|
||||
return;
|
||||
} else if (mParams.intentSender != null) {
|
||||
try {
|
||||
startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
|
||||
mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
|
||||
mParams.extraFlags,
|
||||
mParams.options);
|
||||
return;
|
||||
} catch (SendIntentException e) {
|
||||
mParams.deliverResult(this, RESULT_CANCELED, null);
|
||||
}
|
||||
}
|
||||
finishAndRemoveTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == mParams.requestCode) {
|
||||
mParams.deliverResult(this, resultCode, data);
|
||||
}
|
||||
finishAndRemoveTask();
|
||||
}
|
||||
|
||||
public static Intent getLaunchIntent(Context context, StartActivityParams params) {
|
||||
return new Intent(context, ProxyActivityStarter.class)
|
||||
.putExtra(EXTRA_PARAMS, params)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.proxy;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.PendingIntent.CanceledException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
public class StartActivityParams implements Parcelable {
|
||||
|
||||
private static final String TAG = "StartActivityParams";
|
||||
|
||||
private final PendingIntent mCallback;
|
||||
public final int requestCode;
|
||||
|
||||
public Intent intent;
|
||||
|
||||
public IntentSender intentSender;
|
||||
public Intent fillInIntent;
|
||||
public int flagsMask;
|
||||
public int flagsValues;
|
||||
public int extraFlags;
|
||||
public Bundle options;
|
||||
|
||||
public StartActivityParams(Activity activity, int requestCode) {
|
||||
mCallback = activity.createPendingResult(requestCode, new Intent(),
|
||||
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
this.requestCode = requestCode;
|
||||
}
|
||||
|
||||
private StartActivityParams(Parcel parcel) {
|
||||
mCallback = parcel.readTypedObject(PendingIntent.CREATOR);
|
||||
requestCode = parcel.readInt();
|
||||
intent = parcel.readTypedObject(Intent.CREATOR);
|
||||
|
||||
intentSender = parcel.readTypedObject(IntentSender.CREATOR);
|
||||
fillInIntent = parcel.readTypedObject(Intent.CREATOR);
|
||||
flagsMask = parcel.readInt();
|
||||
flagsValues = parcel.readInt();
|
||||
extraFlags = parcel.readInt();
|
||||
options = parcel.readBundle();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeTypedObject(mCallback, flags);
|
||||
parcel.writeInt(requestCode);
|
||||
parcel.writeTypedObject(intent, flags);
|
||||
|
||||
parcel.writeTypedObject(intentSender, flags);
|
||||
parcel.writeTypedObject(fillInIntent, flags);
|
||||
parcel.writeInt(flagsMask);
|
||||
parcel.writeInt(flagsValues);
|
||||
parcel.writeInt(extraFlags);
|
||||
parcel.writeBundle(options);
|
||||
}
|
||||
|
||||
public void deliverResult(Context context, int resultCode, Intent data) {
|
||||
try {
|
||||
mCallback.send(context, resultCode, data);
|
||||
} catch (CanceledException e) {
|
||||
Log.e(TAG, "Unable to send back result", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<StartActivityParams> CREATOR =
|
||||
new Parcelable.Creator<StartActivityParams>() {
|
||||
public StartActivityParams createFromParcel(Parcel source) {
|
||||
return new StartActivityParams(source);
|
||||
}
|
||||
|
||||
public StartActivityParams[] newArray(int size) {
|
||||
return new StartActivityParams[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.uioverrides;
|
||||
|
||||
import static android.app.Activity.RESULT_CANCELED;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
@@ -31,6 +33,9 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.util.Base64;
|
||||
|
||||
@@ -43,6 +48,8 @@ import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.proxy.ProxyActivityStarter;
|
||||
import com.android.launcher3.proxy.StartActivityParams;
|
||||
import com.android.quickstep.OverviewInteractionState;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
@@ -192,6 +199,40 @@ public class UiFactory extends RecentsUiFactory {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean startIntentSenderForResult(Activity activity, IntentSender intent,
|
||||
int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
|
||||
Bundle options) {
|
||||
StartActivityParams params = new StartActivityParams(activity, requestCode);
|
||||
params.intentSender = intent;
|
||||
params.fillInIntent = fillInIntent;
|
||||
params.flagsMask = flagsMask;
|
||||
params.flagsValues = flagsValues;
|
||||
params.extraFlags = extraFlags;
|
||||
params.options = options;
|
||||
((Context) activity).startActivity(ProxyActivityStarter.getLaunchIntent(activity, params));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean startActivityForResult(Activity activity, Intent intent, int requestCode,
|
||||
Bundle options) {
|
||||
StartActivityParams params = new StartActivityParams(activity, requestCode);
|
||||
params.intent = intent;
|
||||
params.options = options;
|
||||
activity.startActivity(ProxyActivityStarter.getLaunchIntent(activity, params));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any active ProxyActivityStarter task and sends RESULT_CANCELED to Launcher.
|
||||
*
|
||||
* ProxyActivityStarter is started with clear task to reset the task after which it removes the
|
||||
* task itself.
|
||||
*/
|
||||
public static void resetPendingActivityResults(Launcher launcher, int requestCode) {
|
||||
launcher.onActivityResult(requestCode, RESULT_CANCELED, null);
|
||||
launcher.startActivity(ProxyActivityStarter.getLaunchIntent(launcher, null));
|
||||
}
|
||||
|
||||
public static ScaleAndTranslation getOverviewScaleAndTranslationForNormalState(Launcher l) {
|
||||
if (SysUINavigationMode.getMode(l) == Mode.NO_BUTTON) {
|
||||
float offscreenTranslationX = l.getDeviceProfile().widthPx
|
||||
|
||||
@@ -119,6 +119,16 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
mChangeId++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(int taskId) {
|
||||
for (int i = mTasks.size() - 1; i >= 0; i--) {
|
||||
if (mTasks.get(i).key.id == taskId) {
|
||||
mTasks.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onActivityPinned(String packageName, int userId, int taskId,
|
||||
int stackId) {
|
||||
|
||||
@@ -166,6 +166,12 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(int taskId) {
|
||||
Task.TaskKey dummyKey = new Task.TaskKey(taskId, 0, null, null, 0, 0);
|
||||
mThumbnailCache.remove(dummyKey);
|
||||
}
|
||||
|
||||
public void setSystemUiProxy(ISystemUiProxy systemUiProxy) {
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
}
|
||||
|
||||
@@ -186,6 +186,13 @@ public class TaskThumbnailCache {
|
||||
mCache.evictAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cached thumbnail for the given task.
|
||||
*/
|
||||
public void remove(Task.TaskKey key) {
|
||||
mCache.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The cache size.
|
||||
*/
|
||||
|
||||
@@ -79,6 +79,8 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
|
||||
@After
|
||||
public void tearDown() throws Throwable {
|
||||
AppLaunchTracker.INSTANCE.initializeForTesting(null);
|
||||
PredictionUiStateManager.INSTANCE.initializeForTesting(null);
|
||||
mDevice.unfreezeRotation();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,17 +44,12 @@ import com.android.quickstep.views.RecentsView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
@Rule
|
||||
public TestWatcher mFailureWatcher = new TaplTestsLauncher3.FailureWatcher(mDevice);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Launcher theme -->
|
||||
<style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:colorEdgeEffect">#FF757575</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowShowWallpaper">true</item>
|
||||
<item name="folderTextColor">?attr/workspaceTextColor</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:enforceStatusBarContrast">false</item>
|
||||
<item name="android:enforceNavigationBarContrast">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<resources>
|
||||
<!-- Launcher theme -->
|
||||
<style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
|
||||
<style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.Light">
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:colorEdgeEffect">#FF757575</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
|
||||
@@ -44,6 +44,12 @@
|
||||
android:defaultValue="@bool/allow_rotation"
|
||||
android:persistent="true" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="pref_grid_options"
|
||||
android:title="Enable grid options"
|
||||
android:defaultValue="false"
|
||||
android:persistent="true" />
|
||||
|
||||
<androidx.preference.PreferenceScreen
|
||||
android:key="pref_developer_options"
|
||||
android:persistent="false"
|
||||
|
||||
@@ -845,7 +845,8 @@ public class CellLayout extends ViewGroup implements Transposable {
|
||||
* width in {@link DeviceProfile#calculateCellWidth(int, int)}.
|
||||
*/
|
||||
public int getUnusedHorizontalSpace() {
|
||||
return getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth);
|
||||
return (mRotationMode.isTransposed ? getMeasuredHeight() : getMeasuredWidth())
|
||||
- getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth);
|
||||
}
|
||||
|
||||
public Drawable getScrimBackground() {
|
||||
|
||||
@@ -210,9 +210,8 @@ public class DeviceProfile {
|
||||
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
|
||||
hotseatBarSidePaddingEndPx =
|
||||
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
|
||||
// Add a bit of space between nav bar and hotseat in multi-window vertical bar layout.
|
||||
hotseatBarSidePaddingStartPx = isMultiWindowMode && isVerticalBarLayout()
|
||||
? edgeMarginPx : 0;
|
||||
// Add a bit of space between nav bar and hotseat in vertical bar layout.
|
||||
hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? verticalDragHandleSizePx : 0;
|
||||
hotseatBarSizePx = ResourceUtils.pxFromDp(inv.iconSize, dm) + (isVerticalBarLayout()
|
||||
? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
|
||||
: (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
|
||||
|
||||
@@ -72,7 +72,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Toast;
|
||||
@@ -191,6 +190,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
private static final String RUNTIME_STATE = "launcher.state";
|
||||
// Type: PendingRequestArgs
|
||||
private static final String RUNTIME_STATE_PENDING_REQUEST_ARGS = "launcher.request_args";
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_PENDING_REQUEST_CODE = "launcher.request_code";
|
||||
// Type: ActivityResultInfo
|
||||
private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
|
||||
// Type: SparseArray<Parcelable>
|
||||
@@ -264,6 +265,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
* {@link #startActivityForResult(Intent, int)} or {@link #requestPermissions(String[], int)}
|
||||
*/
|
||||
private PendingRequestArgs mPendingRequestArgs;
|
||||
// Request id for any pending activity result
|
||||
private int mPendingActivityRequestCode = -1;
|
||||
|
||||
public ViewGroupFocusHelper mFocusHandler;
|
||||
|
||||
@@ -303,6 +306,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
LauncherAppState app = LauncherAppState.getInstance(this);
|
||||
mOldConfig = new Configuration(getResources().getConfiguration());
|
||||
mModel = app.setLauncher(this);
|
||||
mRotationHelper = new RotationHelper(this);
|
||||
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
|
||||
initDeviceProfile(idp);
|
||||
idp.addOnChangeListener(this);
|
||||
@@ -325,7 +329,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
setupViews();
|
||||
mPopupDataProvider = new PopupDataProvider(this);
|
||||
|
||||
mRotationHelper = new RotationHelper(this);
|
||||
mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
|
||||
|
||||
boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent());
|
||||
@@ -396,12 +399,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
|
||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||
lp.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
|
||||
getWindow().setAttributes(lp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,9 +425,13 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
private boolean supportsFakeLandscapeUI() {
|
||||
return FeatureFlags.FAKE_LANDSCAPE_UI.get() && !mRotationHelper.homeScreenCanRotate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reapplyUi() {
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
|
||||
public void reapplyUi() {
|
||||
if (supportsFakeLandscapeUI()) {
|
||||
mRotationMode = mStableDeviceProfile == null
|
||||
? RotationMode.NORMAL : UiFactory.getRotationMode(mDeviceProfile);
|
||||
}
|
||||
@@ -486,7 +487,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
|
||||
}
|
||||
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get() && mDeviceProfile.isVerticalBarLayout()
|
||||
if (supportsFakeLandscapeUI()
|
||||
&& mDeviceProfile.isVerticalBarLayout()
|
||||
&& !mDeviceProfile.isMultiWindowMode) {
|
||||
mStableDeviceProfile = mDeviceProfile.inv.portraitProfile;
|
||||
mRotationMode = UiFactory.getRotationMode(mDeviceProfile);
|
||||
@@ -763,6 +765,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
@Override
|
||||
public void onActivityResult(
|
||||
final int requestCode, final int resultCode, final Intent data) {
|
||||
mPendingActivityRequestCode = -1;
|
||||
handleActivityResult(requestCode, resultCode, data);
|
||||
if (mLauncherCallbacks != null) {
|
||||
mLauncherCallbacks.onActivityResult(requestCode, resultCode, data);
|
||||
@@ -891,9 +894,21 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
UiFactory.onLauncherStateOrResumeChanged(this);
|
||||
AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
|
||||
resetPendingActivityResultIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetPendingActivityResultIfNeeded() {
|
||||
if (hasBeenResumed() && mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
|
||||
UiFactory.resetPendingActivityResults(this, mPendingActivityRequestCode);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onStateSet(LauncherState state) {
|
||||
getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
|
||||
resetPendingActivityResultIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
RaceConditionTracker.onEvent(ON_RESUME_EVT, ENTER);
|
||||
@@ -1010,6 +1025,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
if (requestArgs != null) {
|
||||
setWaitingForResult(requestArgs);
|
||||
}
|
||||
mPendingActivityRequestCode = savedState.getInt(RUNTIME_STATE_PENDING_REQUEST_CODE);
|
||||
|
||||
mPendingActivityResult = savedState.getParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT);
|
||||
|
||||
@@ -1393,6 +1409,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
if (mPendingRequestArgs != null) {
|
||||
outState.putParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS, mPendingRequestArgs);
|
||||
}
|
||||
outState.putInt(RUNTIME_STATE_PENDING_REQUEST_CODE, mPendingActivityRequestCode);
|
||||
|
||||
if (mPendingActivityResult != null) {
|
||||
outState.putParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT, mPendingActivityResult);
|
||||
}
|
||||
@@ -1449,17 +1467,29 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
@Override
|
||||
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
||||
super.startActivityForResult(intent, requestCode, options);
|
||||
if (requestCode != -1) {
|
||||
mPendingActivityRequestCode = requestCode;
|
||||
}
|
||||
if (requestCode == -1
|
||||
|| !UiFactory.startActivityForResult(this, intent, requestCode, options)) {
|
||||
super.startActivityForResult(intent, requestCode, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startIntentSenderForResult (IntentSender intent, int requestCode,
|
||||
public void startIntentSenderForResult(IntentSender intent, int requestCode,
|
||||
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
|
||||
try {
|
||||
super.startIntentSenderForResult(intent, requestCode,
|
||||
fillInIntent, flagsMask, flagsValues, extraFlags, options);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
throw new ActivityNotFoundException();
|
||||
if (requestCode != -1) {
|
||||
mPendingActivityRequestCode = requestCode;
|
||||
}
|
||||
if (requestCode == -1 || !UiFactory.startIntentSenderForResult(this, intent, requestCode,
|
||||
fillInIntent, flagsMask, flagsValues, extraFlags, options)) {
|
||||
try {
|
||||
super.startIntentSenderForResult(intent, requestCode,
|
||||
fillInIntent, flagsMask, flagsValues, extraFlags, options);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
throw new ActivityNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.launcher3;
|
||||
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
|
||||
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
|
||||
|
||||
import static com.android.launcher3.TestProtocol.ALL_APPS_STATE_ORDINAL;
|
||||
import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
|
||||
import static com.android.launcher3.TestProtocol.NORMAL_STATE_ORDINAL;
|
||||
@@ -203,6 +202,10 @@ public class LauncherState {
|
||||
return UiFactory.getOverviewScaleAndTranslationForNormalState(launcher);
|
||||
}
|
||||
|
||||
public float getOverviewFullscreenProgress() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void onStateEnabled(Launcher launcher) {
|
||||
dispatchWindowStateChanged(launcher);
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ public class LauncherStateManager {
|
||||
}
|
||||
mState = state;
|
||||
mState.onStateEnabled(mLauncher);
|
||||
mLauncher.getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
|
||||
mLauncher.onStateSet(mState);
|
||||
|
||||
if (state.disablePageClipping) {
|
||||
// Only disable clipping if needed, otherwise leave it as previous value.
|
||||
|
||||
@@ -24,6 +24,7 @@ public final class TestProtocol {
|
||||
public static final String SCROLL_Y_FIELD = "scrollY";
|
||||
public static final String STATE_FIELD = "state";
|
||||
public static final String SWITCHED_TO_STATE_MESSAGE = "TAPL_SWITCHED_TO_STATE";
|
||||
public static final String SCROLL_FINISHED_MESSAGE = "TAPL_SCROLL_FINISHED";
|
||||
public static final String RESPONSE_MESSAGE_POSTFIX = "_RESPONSE";
|
||||
public static final int NORMAL_STATE_ORDINAL = 0;
|
||||
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -32,12 +33,16 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.DeadObjectException;
|
||||
@@ -45,6 +50,7 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.TransactionTooLargeException;
|
||||
import android.provider.Settings;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
@@ -62,9 +68,11 @@ import com.android.launcher3.compat.ShortcutConfigActivityInfo;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.views.Transposable;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
|
||||
@@ -82,6 +90,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
|
||||
|
||||
/**
|
||||
* Various utilities shared amongst the Launcher's classes.
|
||||
*/
|
||||
@@ -97,9 +107,7 @@ public final class Utilities {
|
||||
private static final Matrix sMatrix = new Matrix();
|
||||
private static final Matrix sInverseMatrix = new Matrix();
|
||||
|
||||
public static final boolean ATLEAST_Q = Build.VERSION.CODENAME.length() == 1
|
||||
&& Build.VERSION.CODENAME.charAt(0) >= 'Q'
|
||||
&& Build.VERSION.CODENAME.charAt(0) <= 'Z';
|
||||
public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
|
||||
|
||||
public static final boolean ATLEAST_P =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
|
||||
@@ -125,6 +133,11 @@ public final class Utilities {
|
||||
Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
|
||||
Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
|
||||
|
||||
public static boolean isDevelopersOptionsEnabled(Context context) {
|
||||
return Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
|
||||
}
|
||||
|
||||
// An intent extra to indicate the horizontal scroll of the wallpaper.
|
||||
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
|
||||
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
|
||||
@@ -152,6 +165,12 @@ public final class Utilities {
|
||||
return Log.isLoggable(propertyName, Log.VERBOSE);
|
||||
}
|
||||
|
||||
public static boolean existsStyleWallpapers(Context context) {
|
||||
ResolveInfo ri = context.getPackageManager().resolveActivity(
|
||||
PackageManagerHelper.getStyleWallpapersIntent(context), 0);
|
||||
return ri != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
|
||||
* coordinates.
|
||||
@@ -654,6 +673,40 @@ public final class Utilities {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For apps icons and shortcut icons that have badges, this method creates a drawable that can
|
||||
* later on be rendered on top of the layers for the badges. For app icons, work profile badges
|
||||
* can only be applied. For deep shortcuts, when dragged from the pop up container, there's no
|
||||
* badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge
|
||||
**/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public static Drawable getBadge(Launcher launcher, ItemInfo info, Object obj) {
|
||||
LauncherAppState appState = LauncherAppState.getInstance(launcher);
|
||||
int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
|
||||
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
boolean iconBadged = (info instanceof ItemInfoWithIcon)
|
||||
&& (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0;
|
||||
if ((info.id == ItemInfo.NO_ID && !iconBadged)
|
||||
|| !(obj instanceof ShortcutInfo)) {
|
||||
// The item is not yet added on home screen.
|
||||
return new FixedSizeEmptyDrawable(iconSize);
|
||||
}
|
||||
ShortcutInfo si = (ShortcutInfo) obj;
|
||||
LauncherIcons li = LauncherIcons.obtain(appState.getContext());
|
||||
Bitmap badge = li.getShortcutInfoBadge(si, appState.getIconCache()).iconBitmap;
|
||||
li.recycle();
|
||||
float badgeSize = launcher.getResources().getDimension(R.dimen.profile_badge_size);
|
||||
float insetFraction = (iconSize - badgeSize) / iconSize;
|
||||
return new InsetDrawable(new FastBitmapDrawable(badge),
|
||||
insetFraction, insetFraction, 0, 0);
|
||||
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
|
||||
return ((FolderAdaptiveIcon) obj).getBadge();
|
||||
} else {
|
||||
return launcher.getPackageManager()
|
||||
.getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] getIntArrayFromString(String tokenized) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(tokenized, ",");
|
||||
int[] array = new int[tokenizer.countTokens()];
|
||||
@@ -672,4 +725,24 @@ public final class Utilities {
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private static class FixedSizeEmptyDrawable extends ColorDrawable {
|
||||
|
||||
private final int mSize;
|
||||
|
||||
public FixedSizeEmptyDrawable(int size) {
|
||||
super(Color.TRANSPARENT);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
@@ -419,4 +420,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(int state) {
|
||||
super.onScrollStateChanged(state);
|
||||
|
||||
if (state == SCROLL_STATE_IDLE && Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerTyp
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
@@ -32,6 +31,7 @@ import android.view.MotionEvent;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.states.InternalStateHandler;
|
||||
|
||||
@@ -134,7 +134,7 @@ public class DiscoveryBounce extends AbstractFloatingView {
|
||||
&& !shouldShowForWorkProfile(launcher))
|
||||
|| AbstractFloatingView.getTopOpenView(launcher) != null
|
||||
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|
||||
|| ActivityManager.isRunningInTestHarness()) {
|
||||
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class DiscoveryBounce extends AbstractFloatingView {
|
||||
|| (launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
|
||||
&& !shouldShowForWorkProfile(launcher))
|
||||
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|
||||
|| ActivityManager.isRunningInTestHarness()) {
|
||||
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,13 @@ public class AccessibilityManagerCompat {
|
||||
sendEventToTest(accessibilityManager, TestProtocol.SWITCHED_TO_STATE_MESSAGE, parcel);
|
||||
}
|
||||
|
||||
public static void sendScrollFinishedEventToTest(Context context) {
|
||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||
if (accessibilityManager == null) return;
|
||||
|
||||
sendEventToTest(accessibilityManager, TestProtocol.SCROLL_FINISHED_MESSAGE, null);
|
||||
}
|
||||
|
||||
private static void sendEventToTest(
|
||||
AccessibilityManager accessibilityManager, String eventTag, Bundle data) {
|
||||
final AccessibilityEvent e = AccessibilityEvent.obtain(
|
||||
|
||||
@@ -58,9 +58,7 @@ abstract class BaseFlags {
|
||||
}
|
||||
|
||||
public static boolean showFlagTogglerUi(Context context) {
|
||||
return Utilities.IS_DEBUG_DEVICE &&
|
||||
Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
|
||||
return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
|
||||
}
|
||||
|
||||
public static final boolean IS_DOGFOOD_BUILD = false;
|
||||
@@ -111,7 +109,7 @@ abstract class BaseFlags {
|
||||
"Show chip hints and gleams on the overview screen");
|
||||
|
||||
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
|
||||
"FAKE_LANDSCAPE_UI", false,
|
||||
"FAKE_LANDSCAPE_UI", true,
|
||||
"Rotate launcher UI instead of using transposed layout");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
|
||||
import static com.android.launcher3.Utilities.getBadge;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -24,7 +24,6 @@ import android.animation.FloatArrayEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
@@ -37,7 +36,6 @@ import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -45,11 +43,11 @@ import android.view.View;
|
||||
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.FirstFrameAnimatorHelper;
|
||||
@@ -64,7 +62,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
public class DragView extends View {
|
||||
public class DragView extends View implements LauncherStateManager.StateListener {
|
||||
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
|
||||
private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
|
||||
|
||||
@@ -176,6 +174,27 @@ public class DragView extends View {
|
||||
setElevation(getResources().getDimension(R.dimen.drag_elevation));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mLauncher.getStateManager().addStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mLauncher.getStateManager().removeStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateTransitionStart(LauncherState toState) { }
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
setVisibility((finalState == LauncherState.NORMAL
|
||||
|| finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize {@code #mIconDrawable} if the item can be represented using
|
||||
* an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
|
||||
@@ -195,7 +214,6 @@ public class DragView extends View {
|
||||
new Handler(workerLooper).postAtFrontOfQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
|
||||
Object[] outObj = new Object[1];
|
||||
int w = mBitmap.getWidth();
|
||||
int h = mBitmap.getHeight();
|
||||
@@ -211,7 +229,7 @@ public class DragView extends View {
|
||||
// Badge is applied after icon normalization so the bounds for badge should not
|
||||
// be scaled down due to icon normalization.
|
||||
Rect badgeBounds = new Rect(bounds);
|
||||
mBadge = getBadge(info, appState, outObj[0]);
|
||||
mBadge = getBadge(mLauncher, info, outObj[0]);
|
||||
mBadge.setBounds(badgeBounds);
|
||||
|
||||
// Do not draw the background in case of folder as its translucent
|
||||
@@ -307,40 +325,6 @@ public class DragView extends View {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* For apps icons and shortcut icons that have badges, this method creates a drawable that can
|
||||
* later on be rendered on top of the layers for the badges. For app icons, work profile badges
|
||||
* can only be applied. For deep shortcuts, when dragged from the pop up container, there's no
|
||||
* badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge
|
||||
**/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private Drawable getBadge(ItemInfo info, LauncherAppState appState, Object obj) {
|
||||
int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
|
||||
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
boolean iconBadged = (info instanceof ItemInfoWithIcon)
|
||||
&& (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0;
|
||||
if ((info.id == ItemInfo.NO_ID && !iconBadged)
|
||||
|| !(obj instanceof ShortcutInfo)) {
|
||||
// The item is not yet added on home screen.
|
||||
return new FixedSizeEmptyDrawable(iconSize);
|
||||
}
|
||||
ShortcutInfo si = (ShortcutInfo) obj;
|
||||
LauncherIcons li = LauncherIcons.obtain(appState.getContext());
|
||||
Bitmap badge = li.getShortcutInfoBadge(si, appState.getIconCache()).iconBitmap;
|
||||
li.recycle();
|
||||
float badgeSize = mLauncher.getResources().getDimension(R.dimen.profile_badge_size);
|
||||
float insetFraction = (iconSize - badgeSize) / iconSize;
|
||||
return new InsetDrawable(new FastBitmapDrawable(badge),
|
||||
insetFraction, insetFraction, 0, 0);
|
||||
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
|
||||
return ((FolderAdaptiveIcon) obj).getBadge();
|
||||
} else {
|
||||
return mLauncher.getPackageManager()
|
||||
.getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
|
||||
@@ -626,24 +610,4 @@ public class DragView extends View {
|
||||
mSpring.animateToFinalPosition(Utilities.boundToRange(value, -mDelta, mDelta));
|
||||
}
|
||||
}
|
||||
|
||||
private static class FixedSizeEmptyDrawable extends ColorDrawable {
|
||||
|
||||
private final int mSize;
|
||||
|
||||
public FixedSizeEmptyDrawable(int size) {
|
||||
super(Color.TRANSPARENT);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import android.util.Property;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -152,7 +154,8 @@ public class FolderAnimationManager {
|
||||
final float yDistance = initialY - lp.y;
|
||||
|
||||
// Set up the Folder background.
|
||||
final int finalColor = Themes.getAttrColor(mContext, R.attr.folderFillColor);
|
||||
final int finalColor = ColorUtils.setAlphaComponent(
|
||||
Themes.getAttrColor(mContext, R.attr.folderFillColor), 255);
|
||||
final int initialColor = setColorAlphaBound(
|
||||
finalColor, mPreviewBackground.getBackgroundAlpha());
|
||||
mFolderBackground.mutate();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.logging;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -76,8 +77,12 @@ public class EventLogArray {
|
||||
nextIndex = (nextIndex + 1) % logs.length;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Arrays.setAll(logs, (i) -> null);
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter writer) {
|
||||
writer.println(prefix + name + " event history:");
|
||||
writer.println(prefix + "EventLog (" + name + ") history:");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(" HH:mm:ss.SSSZ ", Locale.US);
|
||||
Date date = new Date();
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ import static com.android.launcher3.util.SecureSettingsObserver.newNotificationS
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.Fragment;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
@@ -32,6 +36,7 @@ import com.android.launcher3.LauncherFiles;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.GridOptionsProvider;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.SecureSettingsObserver;
|
||||
|
||||
@@ -47,7 +52,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
|
||||
*/
|
||||
public class SettingsActivity extends Activity
|
||||
implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback {
|
||||
implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener{
|
||||
|
||||
private static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options";
|
||||
private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
|
||||
@@ -61,6 +67,8 @@ public class SettingsActivity extends Activity
|
||||
private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
|
||||
public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
|
||||
|
||||
public static final String GRID_OPTIONS_PREFERENCE_KEY = "pref_grid_options";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -79,6 +87,28 @@ public class SettingsActivity extends Activity
|
||||
.replace(android.R.id.content, f)
|
||||
.commit();
|
||||
}
|
||||
Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (GRID_OPTIONS_PREFERENCE_KEY.equals(key)) {
|
||||
|
||||
final ComponentName cn = new ComponentName(getApplicationContext(),
|
||||
GridOptionsProvider.class);
|
||||
Context c = getApplicationContext();
|
||||
int oldValue = c.getPackageManager().getComponentEnabledSetting(cn);
|
||||
int newValue;
|
||||
if (Utilities.getPrefs(c).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)) {
|
||||
newValue = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
} else {
|
||||
newValue = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
}
|
||||
|
||||
if (oldValue != newValue) {
|
||||
c.getPackageManager().setComponentEnabledSetting(cn, newValue,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean startFragment(String fragment, Bundle args, String key) {
|
||||
@@ -200,6 +230,10 @@ public class SettingsActivity extends Activity
|
||||
// Show if plugins are enabled or flag UI is enabled.
|
||||
return FeatureFlags.showFlagTogglerUi(getContext()) ||
|
||||
PluginManagerWrapper.hasPlugins(getContext());
|
||||
case GRID_OPTIONS_PREFERENCE_KEY:
|
||||
return Utilities.isDevelopersOptionsEnabled(getContext()) &&
|
||||
Utilities.IS_DEBUG_DEVICE &&
|
||||
Utilities.existsStyleWallpapers(getContext());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -20,13 +20,16 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
/**
|
||||
@@ -49,7 +52,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
public static final int REQUEST_ROTATE = 1;
|
||||
public static final int REQUEST_LOCK = 2;
|
||||
|
||||
private final Activity mActivity;
|
||||
private final Launcher mLauncher;
|
||||
private final SharedPreferences mPrefs;
|
||||
|
||||
private boolean mIgnoreAutoRotateSettings;
|
||||
@@ -70,13 +73,13 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private int mLastActivityFlags = -1;
|
||||
|
||||
public RotationHelper(Activity activity) {
|
||||
mActivity = activity;
|
||||
public RotationHelper(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
|
||||
// On large devices we do not handle auto-rotate differently.
|
||||
mIgnoreAutoRotateSettings = mActivity.getResources().getBoolean(R.bool.allow_rotation);
|
||||
mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
|
||||
if (!mIgnoreAutoRotateSettings) {
|
||||
mPrefs = Utilities.getPrefs(mActivity);
|
||||
mPrefs = Utilities.getPrefs(mLauncher);
|
||||
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||
mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
|
||||
getAllowRotationDefaultValue());
|
||||
@@ -85,11 +88,32 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean homeScreenCanRotate() {
|
||||
return mIgnoreAutoRotateSettings || mAutoRotateEnabled
|
||||
|| mStateHandlerRequest != REQUEST_NONE;
|
||||
}
|
||||
|
||||
private void updateRotationAnimation() {
|
||||
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
|
||||
WindowManager.LayoutParams lp = mLauncher.getWindow().getAttributes();
|
||||
lp.rotationAnimation = homeScreenCanRotate()
|
||||
? WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE
|
||||
: WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
|
||||
mLauncher.getWindow().setAttributes(lp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
|
||||
boolean wasRotationEnabled = mAutoRotateEnabled;
|
||||
mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
|
||||
getAllowRotationDefaultValue());
|
||||
notifyChange();
|
||||
if (mAutoRotateEnabled != wasRotationEnabled) {
|
||||
|
||||
notifyChange();
|
||||
updateRotationAnimation();
|
||||
mLauncher.reapplyUi();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStateHandlerRequest(int request) {
|
||||
@@ -109,7 +133,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
// Used by tests only.
|
||||
public void forceAllowRotationForTesting(boolean allowRotation) {
|
||||
mIgnoreAutoRotateSettings =
|
||||
allowRotation || mActivity.getResources().getBoolean(R.bool.allow_rotation);
|
||||
allowRotation || mLauncher.getResources().getBoolean(R.bool.allow_rotation);
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@@ -117,6 +141,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
if (!mInitialized) {
|
||||
mInitialized = true;
|
||||
notifyChange();
|
||||
updateRotationAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +175,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
}
|
||||
if (activityFlags != mLastActivityFlags) {
|
||||
mLastActivityFlags = activityFlags;
|
||||
UiThreadHelper.setOrientationAsync(mActivity, activityFlags);
|
||||
UiThreadHelper.setOrientationAsync(mLauncher, activityFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,11 @@ public class PackageManagerHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static Intent getStyleWallpapersIntent(Context context) {
|
||||
return new Intent(Intent.ACTION_SET_WALLPAPER).setComponent(
|
||||
new ComponentName(context.getString(R.string.wallpaper_picker_package),
|
||||
"com.android.customization.picker.CustomizationPickerActivity"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the details activity for {@code info}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
|
||||
import static com.android.launcher3.Utilities.getBadge;
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
@@ -62,6 +64,9 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
/**
|
||||
* A view that is created to look like another view with the purpose of creating fluid animations.
|
||||
@@ -76,6 +81,39 @@ public class FloatingIconView extends View implements
|
||||
private static final RectF sTmpRectF = new RectF();
|
||||
private static final Object[] sTmpObjArray = new Object[1];
|
||||
|
||||
// We spring the foreground drawable relative to the icon's movement in the DragLayer.
|
||||
// We then use these two factor values to scale the movement of the fg within this view.
|
||||
private static final int FG_TRANS_X_FACTOR = 80;
|
||||
private static final int FG_TRANS_Y_FACTOR = 100;
|
||||
|
||||
private static final FloatPropertyCompat<FloatingIconView> mFgTransYProperty
|
||||
= new FloatPropertyCompat<FloatingIconView>("FloatingViewFgTransY") {
|
||||
@Override
|
||||
public float getValue(FloatingIconView view) {
|
||||
return view.mFgTransY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(FloatingIconView view, float transY) {
|
||||
view.mFgTransY = transY;
|
||||
view.invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
private static final FloatPropertyCompat<FloatingIconView> mFgTransXProperty
|
||||
= new FloatPropertyCompat<FloatingIconView>("FloatingViewFgTransX") {
|
||||
@Override
|
||||
public float getValue(FloatingIconView view) {
|
||||
return view.mFgTransX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(FloatingIconView view, float transX) {
|
||||
view.mFgTransX = transX;
|
||||
view.invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
private Runnable mEndRunnable;
|
||||
private CancellationSignal mLoadIconSignal;
|
||||
|
||||
@@ -85,6 +123,7 @@ public class FloatingIconView extends View implements
|
||||
private boolean mIsVerticalBarLayout = false;
|
||||
private boolean mIsAdaptiveIcon = false;
|
||||
|
||||
private @Nullable Drawable mBadge;
|
||||
private @Nullable Drawable mForeground;
|
||||
private @Nullable Drawable mBackground;
|
||||
private float mRotation;
|
||||
@@ -100,17 +139,30 @@ public class FloatingIconView extends View implements
|
||||
|
||||
private final Rect mOutline = new Rect();
|
||||
private final Rect mFinalDrawableBounds = new Rect();
|
||||
private final Rect mBgDrawableBounds = new Rect();
|
||||
|
||||
private AnimatorSet mFadeAnimatorSet;
|
||||
private ListenerView mListenerView;
|
||||
|
||||
private final SpringAnimation mFgSpringY;
|
||||
private float mFgTransY;
|
||||
private final SpringAnimation mFgSpringX;
|
||||
private float mFgTransX;
|
||||
|
||||
private FloatingIconView(Launcher launcher) {
|
||||
super(launcher);
|
||||
mLauncher = launcher;
|
||||
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
||||
R.dimen.blur_size_medium_outline);
|
||||
mListenerView = new ListenerView(launcher, null);
|
||||
|
||||
mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
|
||||
.setSpring(new SpringForce()
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW));
|
||||
mFgSpringY = new SpringAnimation(this, mFgTransYProperty)
|
||||
.setSpring(new SpringForce()
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,7 +210,12 @@ public class FloatingIconView extends View implements
|
||||
Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
|
||||
LINEAR), 0, 1);
|
||||
|
||||
mOutline.bottom = (int) (rect.height() / scale);
|
||||
if (mIsVerticalBarLayout) {
|
||||
mOutline.right = (int) (rect.width() / scale);
|
||||
} else {
|
||||
mOutline.bottom = (int) (rect.height() / scale);
|
||||
}
|
||||
|
||||
mTaskCornerRadius = cornerRadius / scale;
|
||||
if (mIsAdaptiveIcon) {
|
||||
if (!isOpening && shapeRevealProgress >= 0) {
|
||||
@@ -178,7 +235,32 @@ public class FloatingIconView extends View implements
|
||||
mRevealAnimator.setCurrentFraction(shapeRevealProgress);
|
||||
}
|
||||
|
||||
setBackgroundDrawableBounds(mOutline.height() / minSize);
|
||||
float drawableScale = (mIsVerticalBarLayout ? mOutline.width() : mOutline.height())
|
||||
/ minSize;
|
||||
setBackgroundDrawableBounds(drawableScale);
|
||||
if (isOpening) {
|
||||
// Center align foreground
|
||||
int height = mFinalDrawableBounds.height();
|
||||
int width = mFinalDrawableBounds.width();
|
||||
int diffY = mIsVerticalBarLayout ? 0
|
||||
: (int) (((height * drawableScale) - height) / 2);
|
||||
int diffX = mIsVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
|
||||
: 0;
|
||||
sTmpRect.set(mFinalDrawableBounds);
|
||||
sTmpRect.offset(diffX, diffY);
|
||||
mForeground.setBounds(sTmpRect);
|
||||
} else {
|
||||
// Spring the foreground relative to the icon's movement within the DragLayer.
|
||||
int diffX = (int) (dX / mLauncher.getDeviceProfile().availableWidthPx
|
||||
* FG_TRANS_X_FACTOR);
|
||||
int diffY = (int) (dY / mLauncher.getDeviceProfile().availableHeightPx
|
||||
* FG_TRANS_Y_FACTOR);
|
||||
|
||||
mFgSpringX.animateToFinalPosition(diffX);
|
||||
mFgSpringY.animateToFinalPosition(diffY);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
invalidate();
|
||||
invalidateOutline();
|
||||
@@ -289,7 +371,9 @@ public class FloatingIconView extends View implements
|
||||
if (supportsAdaptiveIcons) {
|
||||
drawable = Utilities.getFullDrawable(mLauncher, info, lp.width, lp.height,
|
||||
false, sTmpObjArray);
|
||||
if (!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
if ((drawable instanceof AdaptiveIconDrawable)) {
|
||||
mBadge = getBadge(mLauncher, info, sTmpObjArray[0]);
|
||||
} else {
|
||||
// The drawable we get back is not an adaptive icon, so we need to use the
|
||||
// BubbleTextView icon that is already legacy treated.
|
||||
drawable = btvIcon;
|
||||
@@ -348,8 +432,17 @@ public class FloatingIconView extends View implements
|
||||
|
||||
mStartRevealRect.set(0, 0, originalWidth, originalHeight);
|
||||
|
||||
if (mBadge != null) {
|
||||
mBadge.setBounds(mStartRevealRect);
|
||||
if (!isOpening) {
|
||||
DRAWABLE_ALPHA.set(mBadge, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isFolderIcon) {
|
||||
mStartRevealRect.inset(mBlurSizeOutline, mBlurSizeOutline);
|
||||
Utilities.scaleRectAboutCenter(mStartRevealRect,
|
||||
IconShape.getNormalizationScale());
|
||||
}
|
||||
|
||||
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
|
||||
@@ -393,17 +486,15 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
|
||||
private void setBackgroundDrawableBounds(float scale) {
|
||||
mBgDrawableBounds.set(mFinalDrawableBounds);
|
||||
Utilities.scaleRectAboutCenter(mBgDrawableBounds, scale);
|
||||
sTmpRect.set(mFinalDrawableBounds);
|
||||
Utilities.scaleRectAboutCenter(sTmpRect, scale);
|
||||
// Since the drawable is at the top of the view, we need to offset to keep it centered.
|
||||
if (mIsVerticalBarLayout) {
|
||||
mBgDrawableBounds.offsetTo((int) (mFinalDrawableBounds.left * scale),
|
||||
mBgDrawableBounds.top);
|
||||
sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
|
||||
} else {
|
||||
mBgDrawableBounds.offsetTo(mBgDrawableBounds.left,
|
||||
(int) (mFinalDrawableBounds.top * scale));
|
||||
sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
|
||||
}
|
||||
mBackground.setBounds(mBgDrawableBounds);
|
||||
mBackground.setBounds(sTmpRect);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -448,7 +539,13 @@ public class FloatingIconView extends View implements
|
||||
mBackground.draw(canvas);
|
||||
}
|
||||
if (mForeground != null) {
|
||||
int count2 = canvas.save();
|
||||
canvas.translate(mFgTransX, mFgTransY);
|
||||
mForeground.draw(canvas);
|
||||
canvas.restoreToCount(count2);
|
||||
}
|
||||
if (mBadge != null) {
|
||||
mBadge.draw(canvas);
|
||||
}
|
||||
canvas.restoreToCount(count);
|
||||
}
|
||||
@@ -568,6 +665,12 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
});
|
||||
|
||||
if (mBadge != null) {
|
||||
ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
|
||||
badgeFade.addUpdateListener(valueAnimator -> invalidate());
|
||||
fade.play(badgeFade);
|
||||
}
|
||||
|
||||
if (originalView instanceof BubbleTextView) {
|
||||
BubbleTextView btv = (BubbleTextView) originalView;
|
||||
btv.forceHideDot(true);
|
||||
@@ -624,7 +727,6 @@ public class FloatingIconView extends View implements
|
||||
mBackground = null;
|
||||
mClipPath = null;
|
||||
mFinalDrawableBounds.setEmpty();
|
||||
mBgDrawableBounds.setEmpty();
|
||||
if (mRevealAnimator != null) {
|
||||
mRevealAnimator.cancel();
|
||||
}
|
||||
@@ -639,5 +741,10 @@ public class FloatingIconView extends View implements
|
||||
mOnTargetChangeRunnable = null;
|
||||
mTaskCornerRadius = 0;
|
||||
mOutline.setEmpty();
|
||||
mFgTransY = 0;
|
||||
mFgSpringX.cancel();
|
||||
mFgTransX = 0;
|
||||
mFgSpringY.cancel();
|
||||
mBadge = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,9 +152,9 @@ public class OptionsPopupView extends ArrowPopup
|
||||
RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
|
||||
|
||||
ArrayList<OptionItem> options = new ArrayList<>();
|
||||
int resString = existsStyleWallpapers(launcher) ?
|
||||
int resString = Utilities.existsStyleWallpapers(launcher) ?
|
||||
R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
|
||||
int resDrawable = existsStyleWallpapers(launcher) ?
|
||||
int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
|
||||
R.drawable.ic_palette : R.drawable.ic_wallpaper;
|
||||
options.add(new OptionItem(resString, resDrawable,
|
||||
ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
|
||||
@@ -168,14 +168,6 @@ public class OptionsPopupView extends ArrowPopup
|
||||
show(launcher, target, options);
|
||||
}
|
||||
|
||||
private static boolean existsStyleWallpapers(Launcher launcher) {
|
||||
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
|
||||
intent.setComponent(new ComponentName(launcher.getString(R.string.wallpaper_picker_package),
|
||||
"com.android.customization.picker.CustomizationPickerActivity"));
|
||||
ResolveInfo ri = launcher.getPackageManager().resolveActivity(intent, 0);
|
||||
return ri != null;
|
||||
}
|
||||
|
||||
public static boolean onWidgetsClicked(View view) {
|
||||
return openWidgets(Launcher.getLauncher(view.getContext()));
|
||||
}
|
||||
@@ -212,7 +204,7 @@ public class OptionsPopupView extends ArrowPopup
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.putExtra(EXTRA_WALLPAPER_OFFSET,
|
||||
launcher.getWorkspace().getWallpaperOffsetForCenterPage());
|
||||
if (!existsStyleWallpapers(launcher)) {
|
||||
if (!Utilities.existsStyleWallpapers(launcher)) {
|
||||
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
|
||||
} else {
|
||||
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper");
|
||||
|
||||
@@ -18,6 +18,9 @@ package com.android.launcher3.uioverrides;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -79,4 +82,18 @@ public class UiFactory {
|
||||
public static RotationMode getRotationMode(DeviceProfile dp) {
|
||||
return RotationMode.NORMAL;
|
||||
}
|
||||
|
||||
public static boolean startIntentSenderForResult(Activity activity, IntentSender intent,
|
||||
int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
|
||||
Bundle options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean startActivityForResult(Activity activity, Intent intent, int requestCode,
|
||||
Bundle options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void resetPendingActivityResults(Launcher launcher, int requestCode) { }
|
||||
|
||||
}
|
||||
|
||||
@@ -64,8 +64,12 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -89,23 +93,22 @@ public abstract class AbstractLauncherUiTest {
|
||||
public static final long DEFAULT_UI_TIMEOUT = 10000;
|
||||
protected static final int LONG_WAIT_TIME_MS = 60000;
|
||||
private static final String TAG = "AbstractLauncherUiTest";
|
||||
private static int sScreenshotCount = 0;
|
||||
|
||||
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
|
||||
protected final UiDevice mDevice;
|
||||
protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
|
||||
protected final LauncherInstrumentation mLauncher;
|
||||
protected Context mTargetContext;
|
||||
protected String mTargetPackage;
|
||||
|
||||
protected AbstractLauncherUiTest() {
|
||||
final Instrumentation instrumentation = getInstrumentation();
|
||||
mDevice = UiDevice.getInstance(instrumentation);
|
||||
try {
|
||||
mDevice.setOrientationNatural();
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
|
||||
mLauncher = new LauncherInstrumentation(instrumentation);
|
||||
mLauncher = new LauncherInstrumentation(getInstrumentation());
|
||||
}
|
||||
|
||||
@Rule
|
||||
@@ -163,6 +166,36 @@ public abstract class AbstractLauncherUiTest {
|
||||
}
|
||||
} : base;
|
||||
|
||||
@Rule
|
||||
public TestWatcher mFailureWatcher = new TestWatcher() {
|
||||
private void dumpViewHierarchy() {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
mDevice.dumpWindowHierarchy(stream);
|
||||
stream.flush();
|
||||
stream.close();
|
||||
for (String line : stream.toString().split("\\r?\\n")) {
|
||||
Log.e(TAG, line.trim());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "error dumping XML to logcat", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed(Throwable e, Description description) {
|
||||
if (mDevice == null) return;
|
||||
final String pathname = getInstrumentation().getTargetContext().
|
||||
getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
|
||||
Log.e(TAG, "Failed test " + description.getMethodName() +
|
||||
", screenshot will be saved to " + pathname +
|
||||
", track trace is below, UI object dump is further below:\n" +
|
||||
Log.getStackTraceString(e));
|
||||
dumpViewHierarchy();
|
||||
mDevice.takeScreenshot(new File(pathname));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTargetContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
@@ -24,11 +24,8 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
@@ -45,62 +42,14 @@ import com.android.launcher3.widget.WidgetsFullSheet;
|
||||
import com.android.launcher3.widget.WidgetsRecyclerView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
private static final String TAG = "TaplTestsAosp";
|
||||
private static final String APP_NAME = "LauncherTestApp";
|
||||
|
||||
private static int sScreenshotCount = 0;
|
||||
|
||||
public static class FailureWatcher extends TestWatcher {
|
||||
private UiDevice mDevice;
|
||||
|
||||
public FailureWatcher(UiDevice device) {
|
||||
this.mDevice = device;
|
||||
}
|
||||
|
||||
private void dumpViewHierarchy() {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
mDevice.dumpWindowHierarchy(stream);
|
||||
stream.flush();
|
||||
stream.close();
|
||||
for (String line : stream.toString().split("\\r?\\n")) {
|
||||
Log.e(TAG, line.trim());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "error dumping XML to logcat", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed(Throwable e, Description description) {
|
||||
if (mDevice == null) return;
|
||||
final String pathname = getInstrumentation().getTargetContext().
|
||||
getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
|
||||
Log.e(TAG, "Failed test " + description.getMethodName() +
|
||||
", screenshot will be saved to " + pathname +
|
||||
", track trace is below, UI object dump is further below:\n" +
|
||||
Log.getStackTraceString(e));
|
||||
dumpViewHierarchy();
|
||||
mDevice.takeScreenshot(new File(pathname));
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestWatcher mFailureWatcher = new FailureWatcher(mDevice);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -17,26 +17,25 @@ package com.android.launcher3.ui.widget;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
import androidx.test.uiautomator.Until;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace.ItemOperator;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
|
||||
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
|
||||
@@ -49,7 +48,6 @@ import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
import com.android.launcher3.widget.WidgetCell;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -181,7 +179,9 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
|
||||
|
||||
// Accept confirmation:
|
||||
BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction);
|
||||
mDevice.wait(Until.findObject(By.text("Add automatically")), DEFAULT_UI_TIMEOUT).click();
|
||||
mDevice.wait(Until.findObject(
|
||||
By.text(mLauncher.isAvd() ? "ADD AUTOMATICALLY" : "Add automatically")),
|
||||
DEFAULT_UI_TIMEOUT).click();
|
||||
Intent result = resultReceiver.blockingGetIntent();
|
||||
assertNotNull(result);
|
||||
mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.launcher3.tapl;
|
||||
|
||||
import static com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.uiautomator.BySelector;
|
||||
import androidx.test.uiautomator.Direction;
|
||||
@@ -32,7 +34,6 @@ import com.android.launcher3.TestProtocol;
|
||||
public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
private static final int MAX_SCROLL_ATTEMPTS = 40;
|
||||
private static final int MIN_INTERACT_SIZE = 100;
|
||||
private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 1000 : 3000;
|
||||
|
||||
private final int mHeight;
|
||||
|
||||
@@ -102,7 +103,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
"search_container_all_apps");
|
||||
|
||||
int attempts = 0;
|
||||
allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
|
||||
final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
|
||||
|
||||
for (int scroll = getScroll(allAppsContainer);
|
||||
scroll != 0;
|
||||
@@ -113,7 +114,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
|
||||
++attempts <= MAX_SCROLL_ATTEMPTS);
|
||||
|
||||
allAppsContainer.scroll(Direction.UP, 1);
|
||||
mLauncher.scroll(allAppsContainer, Direction.UP, 1, margins, 50);
|
||||
}
|
||||
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
|
||||
@@ -133,7 +134,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
// Try to figure out how much percentage of the container needs to be scrolled in order
|
||||
// to reveal the app icon to have the MIN_INTERACT_SIZE
|
||||
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
|
||||
allAppsContainer.scroll(Direction.DOWN, pct);
|
||||
mLauncher.scroll(allAppsContainer, Direction.DOWN, pct, null, 10);
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"scrolled an icon in all apps to make it visible - and then")) {
|
||||
mLauncher.waitForIdle();
|
||||
@@ -150,9 +151,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
mLauncher.addContextLayer("want to fling forward in all apps")) {
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
// Start the gesture in the center to avoid starting at elements near the top.
|
||||
allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
|
||||
allAppsContainer.fling(Direction.DOWN,
|
||||
(int) (FLING_SPEED * mLauncher.getDisplayDensity()));
|
||||
mLauncher.scroll(
|
||||
allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10);
|
||||
verifyActiveContainer();
|
||||
}
|
||||
}
|
||||
@@ -165,9 +165,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
mLauncher.addContextLayer("want to fling backward in all apps")) {
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
// Start the gesture in the center, for symmetry with forward.
|
||||
allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
|
||||
allAppsContainer.fling(Direction.UP,
|
||||
(int) (FLING_SPEED * mLauncher.getDisplayDensity()));
|
||||
mLauncher.scroll(
|
||||
allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10);
|
||||
verifyActiveContainer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
* Common overview pane for both Launcher and fallback recents
|
||||
*/
|
||||
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 500 : 1500;
|
||||
private static final int FLING_SPEED = LauncherInstrumentation.isAvd() ? 500 : 1500;
|
||||
private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
|
||||
|
||||
BaseOverview(LauncherInstrumentation launcher) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -47,6 +48,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.BySelector;
|
||||
import androidx.test.uiautomator.Configurator;
|
||||
import androidx.test.uiautomator.Direction;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
import androidx.test.uiautomator.Until;
|
||||
@@ -56,6 +58,7 @@ import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Deque;
|
||||
@@ -195,7 +198,7 @@ public final class LauncherInstrumentation {
|
||||
return NavigationModel.THREE_BUTTON;
|
||||
}
|
||||
|
||||
public static boolean needSlowGestures() {
|
||||
public static boolean isAvd() {
|
||||
return Build.MODEL.contains("Cuttlefish");
|
||||
}
|
||||
|
||||
@@ -212,7 +215,22 @@ public final class LauncherInstrumentation {
|
||||
};
|
||||
}
|
||||
|
||||
private void dumpViewHierarchy() {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
mDevice.dumpWindowHierarchy(stream);
|
||||
stream.flush();
|
||||
stream.close();
|
||||
for (String line : stream.toString().split("\\r?\\n")) {
|
||||
Log.e(TAG, line.trim());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "error dumping XML to logcat", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void fail(String message) {
|
||||
dumpViewHierarchy();
|
||||
Assert.fail("http://go/tapl : " + getContextDescription() + message);
|
||||
}
|
||||
|
||||
@@ -363,10 +381,10 @@ public final class LauncherInstrumentation {
|
||||
? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL;
|
||||
final Point displaySize = getRealDisplaySize();
|
||||
|
||||
swipeViaMovePointer(
|
||||
swipeToState(
|
||||
displaySize.x / 2, displaySize.y - 1,
|
||||
displaySize.x / 2, 0,
|
||||
finalState, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
|
||||
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, finalState);
|
||||
}
|
||||
} else {
|
||||
log(action = "clicking home button");
|
||||
@@ -529,6 +547,14 @@ public final class LauncherInstrumentation {
|
||||
return object;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
UiObject2 waitForLauncherObjectByClass(String clazz) {
|
||||
final BySelector selector = getLauncherObjectSelectorByClass(clazz);
|
||||
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
|
||||
assertNotNull("Can't find a launcher object; selector: " + selector, object);
|
||||
return object;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
UiObject2 waitForFallbackLauncherObject(String resName) {
|
||||
final BySelector selector = getFallbackLauncherObjectSelector(resName);
|
||||
@@ -541,6 +567,10 @@ public final class LauncherInstrumentation {
|
||||
return By.res(getLauncherPackageName(), resName);
|
||||
}
|
||||
|
||||
BySelector getLauncherObjectSelectorByClass(String clazz) {
|
||||
return By.pkg(getLauncherPackageName()).clazz(clazz);
|
||||
}
|
||||
|
||||
BySelector getFallbackLauncherObjectSelector(String resName) {
|
||||
return By.res(getOverviewPackageName(), resName);
|
||||
}
|
||||
@@ -563,18 +593,63 @@ public final class LauncherInstrumentation {
|
||||
() -> mDevice.swipe(startX, startY, endX, endY, steps));
|
||||
}
|
||||
|
||||
void swipeViaMovePointer(
|
||||
int startX, int startY, int endX, int endY, int expectedState, int steps) {
|
||||
changeStateViaGesture(startX, startY, endX, endY, expectedState, () -> {
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
final Point start = new Point(startX, startY);
|
||||
final Point end = new Point(endX, endY);
|
||||
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
|
||||
final long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start,
|
||||
end);
|
||||
sendPointer(
|
||||
downTime, endTime, MotionEvent.ACTION_UP, end);
|
||||
});
|
||||
void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
|
||||
changeStateViaGesture(startX, startY, endX, endY, expectedState,
|
||||
() -> linearGesture(startX, startY, endX, endY, steps));
|
||||
}
|
||||
|
||||
void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
|
||||
final Rect rect = container.getVisibleBounds();
|
||||
if (margins != null) {
|
||||
rect.left += margins.left;
|
||||
rect.top += margins.top;
|
||||
rect.right -= margins.right;
|
||||
rect.bottom -= margins.bottom;
|
||||
}
|
||||
|
||||
final int startX;
|
||||
final int startY;
|
||||
final int endX;
|
||||
final int endY;
|
||||
|
||||
switch (direction) {
|
||||
case UP: {
|
||||
startX = endX = rect.centerX();
|
||||
final int vertCenter = rect.centerY();
|
||||
final float halfGestureHeight = rect.height() * percent / 2.0f;
|
||||
startY = (int) (vertCenter - halfGestureHeight);
|
||||
endY = (int) (vertCenter + halfGestureHeight);
|
||||
}
|
||||
break;
|
||||
case DOWN: {
|
||||
startX = endX = rect.centerX();
|
||||
final int vertCenter = rect.centerY();
|
||||
final float halfGestureHeight = rect.height() * percent / 2.0f;
|
||||
startY = (int) (vertCenter + halfGestureHeight);
|
||||
endY = (int) (vertCenter - halfGestureHeight);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fail("Unsupported direction");
|
||||
return;
|
||||
}
|
||||
|
||||
executeAndWaitForEvent(
|
||||
() -> linearGesture(startX, startY, endX, endY, steps),
|
||||
event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
|
||||
"Didn't receive a scroll end message: " + startX + ", " + startY
|
||||
+ ", " + endX + ", " + endY);
|
||||
}
|
||||
|
||||
// Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
|
||||
// fixed interval each time.
|
||||
private void linearGesture(int startX, int startY, int endX, int endY, int steps) {
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
final Point start = new Point(startX, startY);
|
||||
final Point end = new Point(endX, endY);
|
||||
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
|
||||
final long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
|
||||
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
|
||||
}
|
||||
|
||||
private void changeStateViaGesture(int startX, int startY, int endX, int endY,
|
||||
@@ -688,10 +763,7 @@ public final class LauncherInstrumentation {
|
||||
}
|
||||
|
||||
static void sleep(int duration) {
|
||||
try {
|
||||
Thread.sleep(duration);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
SystemClock.sleep(duration);
|
||||
}
|
||||
|
||||
int getEdgeSensitivityWidth() {
|
||||
|
||||
@@ -49,13 +49,14 @@ public final class Overview extends BaseOverview {
|
||||
"want to switch from overview to all apps")) {
|
||||
verifyActiveContainer();
|
||||
|
||||
// Swipe from the prediction row to the top.
|
||||
// Swipe from an app icon to the top.
|
||||
LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
|
||||
final UiObject2 predictionRow = mLauncher.waitForLauncherObject("prediction_row");
|
||||
mLauncher.swipe(mLauncher.getDevice().getDisplayWidth() / 2,
|
||||
predictionRow.getVisibleBounds().centerY(),
|
||||
final UiObject2 appIcon = mLauncher.waitForLauncherObjectByClass(
|
||||
"android.widget.TextView");
|
||||
mLauncher.swipeToState(mLauncher.getDevice().getDisplayWidth() / 2,
|
||||
appIcon.getVisibleBounds().centerY(),
|
||||
mLauncher.getDevice().getDisplayWidth() / 2,
|
||||
0, ALL_APPS_STATE_ORDINAL);
|
||||
0, 50, ALL_APPS_STATE_ORDINAL);
|
||||
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
|
||||
"swiped all way up from overview")) {
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.android.launcher3.TestProtocol;
|
||||
*/
|
||||
public final class Workspace extends Home {
|
||||
private static final float FLING_SPEED =
|
||||
LauncherInstrumentation.needSlowGestures() ? 1500.0F : 3500.0F;
|
||||
LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F;
|
||||
private static final int DRAG_DURACTION = 2000;
|
||||
private final UiObject2 mHotseat;
|
||||
|
||||
@@ -65,13 +65,14 @@ public final class Workspace extends Home {
|
||||
LauncherInstrumentation.log(
|
||||
"switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
|
||||
+ mLauncher.getTouchSlop());
|
||||
mLauncher.swipe(
|
||||
|
||||
mLauncher.swipeToState(
|
||||
start.x,
|
||||
start.y,
|
||||
start.x,
|
||||
start.y - swipeHeight - mLauncher.getTouchSlop(),
|
||||
ALL_APPS_STATE_ORDINAL
|
||||
);
|
||||
60,
|
||||
ALL_APPS_STATE_ORDINAL);
|
||||
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
|
||||
"swiped to all apps")) {
|
||||
|
||||
Reference in New Issue
Block a user