Merging from ub-launcher3-master @ build 6682763
Test: manual, presubmit on the source branch x20/teams/android-launcher/merge/ub-launcher3-master_master_6682763.html Change-Id: Ibff46b3ef7ff89accb459db323f31179adb4ef21
This commit is contained in:
@@ -45,9 +45,6 @@
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
|
||||
<!-- TODO(b/150802536): Enabled only for ENABLE_FIXED_ROTATION_TRANSFORM feature flag -->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
|
||||
<!--
|
||||
Permissions required for read/write access to the workspace data. These permission name
|
||||
|
||||
@@ -164,6 +164,12 @@ public class DebugTestInformationHandler extends TestInformationHandler {
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
|
||||
if (sEvents == null) {
|
||||
// sEvents can be null if Launcher died and restarted after
|
||||
// REQUEST_START_EVENT_LOGGING.
|
||||
return response;
|
||||
}
|
||||
|
||||
synchronized (sEvents) {
|
||||
response.putStringArrayList(
|
||||
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.android.launcher3">
|
||||
|
||||
<permission
|
||||
<permission
|
||||
android:name="${packageName}.permission.HOTSEAT_EDU"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
android:protectionLevel="signatureOrSystem" />
|
||||
|
||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
|
||||
|
||||
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||
@@ -94,12 +94,11 @@
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
+1
-12
@@ -69,7 +69,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
|
||||
// Accessed only on worker thread
|
||||
private AppPredictor mHomeAppPredictor;
|
||||
private AppPredictor mRecentsOverviewPredictor;
|
||||
|
||||
public PredictionAppTracker(Context context) {
|
||||
mContext = context;
|
||||
@@ -97,10 +96,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
mHomeAppPredictor.destroy();
|
||||
mHomeAppPredictor = null;
|
||||
}
|
||||
if (mRecentsOverviewPredictor != null) {
|
||||
mRecentsOverviewPredictor.destroy();
|
||||
mRecentsOverviewPredictor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -142,7 +137,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
// Initialize the clients
|
||||
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
|
||||
mHomeAppPredictor = createPredictor(Client.HOME, count);
|
||||
mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count);
|
||||
return true;
|
||||
}
|
||||
case MSG_DESTROY: {
|
||||
@@ -157,12 +151,7 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||
}
|
||||
case MSG_PREDICT: {
|
||||
if (mHomeAppPredictor != null) {
|
||||
String client = (String) msg.obj;
|
||||
if (Client.HOME.id.equals(client)) {
|
||||
mHomeAppPredictor.requestPredictionUpdate();
|
||||
} else {
|
||||
mRecentsOverviewPredictor.requestPredictionUpdate();
|
||||
}
|
||||
mHomeAppPredictor.requestPredictionUpdate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+6
-28
@@ -75,8 +75,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
|
||||
// TODO (b/129421797): Update the client constants
|
||||
public enum Client {
|
||||
HOME("home"),
|
||||
OVERVIEW("overview");
|
||||
HOME("home");
|
||||
|
||||
public final String id;
|
||||
|
||||
@@ -91,10 +90,9 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
private final Context mContext;
|
||||
|
||||
private final DynamicItemCache mDynamicItemCache;
|
||||
private final List[] mPredictionServicePredictions;
|
||||
private List mPredictionServicePredictions = Collections.emptyList();
|
||||
|
||||
private int mMaxIconsPerRow;
|
||||
private Client mActiveClient;
|
||||
|
||||
private AllAppsContainerView mAppsView;
|
||||
|
||||
@@ -108,16 +106,10 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
|
||||
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
|
||||
|
||||
mActiveClient = Client.HOME;
|
||||
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
mMaxIconsPerRow = idp.numColumns;
|
||||
|
||||
idp.addOnChangeListener(this);
|
||||
mPredictionServicePredictions = new List[Client.values().length];
|
||||
for (int i = 0; i < mPredictionServicePredictions.length; i++) {
|
||||
mPredictionServicePredictions[i] = Collections.emptyList();
|
||||
}
|
||||
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
|
||||
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
|
||||
|
||||
@@ -130,18 +122,6 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
mMaxIconsPerRow = profile.numColumns;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return mActiveClient;
|
||||
}
|
||||
|
||||
public void switchClient(Client client) {
|
||||
if (client == mActiveClient) {
|
||||
return;
|
||||
}
|
||||
mActiveClient = client;
|
||||
dispatchOnChange(true);
|
||||
}
|
||||
|
||||
public void setTargetAppsView(AllAppsContainerView appsView) {
|
||||
if (mAppsView != null) {
|
||||
mAppsView.getAppsStore().removeUpdateListener(this);
|
||||
@@ -195,10 +175,8 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
}
|
||||
|
||||
private void updatePredictionStateAfterCallback() {
|
||||
boolean validResults = false;
|
||||
for (List l : mPredictionServicePredictions) {
|
||||
validResults |= l != null && !l.isEmpty();
|
||||
}
|
||||
boolean validResults = mPredictionServicePredictions != null
|
||||
&& !mPredictionServicePredictions.isEmpty();
|
||||
if (validResults != mGettingValidPredictionResults) {
|
||||
mGettingValidPredictionResults = validResults;
|
||||
Utilities.getDevicePrefs(mContext).edit()
|
||||
@@ -210,7 +188,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
|
||||
public AppPredictor.Callback appPredictorCallback(Client client) {
|
||||
return targets -> {
|
||||
mPredictionServicePredictions[client.ordinal()] = targets;
|
||||
mPredictionServicePredictions = targets;
|
||||
updatePredictionStateAfterCallback();
|
||||
};
|
||||
}
|
||||
@@ -238,7 +216,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
|
||||
state.apps = new ArrayList<>();
|
||||
|
||||
List<AppTarget> appTargets = mPredictionServicePredictions[mActiveClient.ordinal()];
|
||||
List<AppTarget> appTargets = mPredictionServicePredictions;
|
||||
if (!appTargets.isEmpty()) {
|
||||
for (AppTarget appTarget : appTargets) {
|
||||
ComponentKey key;
|
||||
|
||||
+7
-5
@@ -24,6 +24,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.util.Log;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
@@ -52,17 +53,17 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||
|
||||
private final BaseActivityInterface<?, T> mActivityInterface;
|
||||
// The id of the currently running task that is transitioning to overview.
|
||||
private final int mTargetTaskId;
|
||||
private final RunningTaskInfo mTargetTask;
|
||||
private final RecentsAnimationDeviceState mDeviceState;
|
||||
|
||||
private T mActivity;
|
||||
private RecentsView mRecentsView;
|
||||
|
||||
AppToOverviewAnimationProvider(
|
||||
BaseActivityInterface<?, T> activityInterface, int targetTaskId,
|
||||
BaseActivityInterface<?, T> activityInterface, RunningTaskInfo targetTask,
|
||||
RecentsAnimationDeviceState deviceState) {
|
||||
mActivityInterface = activityInterface;
|
||||
mTargetTaskId = targetTaskId;
|
||||
mTargetTask = targetTask;
|
||||
mDeviceState = deviceState;
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||
* @param wasVisible true if it was visible before
|
||||
*/
|
||||
boolean onActivityReady(T activity, Boolean wasVisible) {
|
||||
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
|
||||
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTask);
|
||||
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
|
||||
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
|
||||
mDeviceState,
|
||||
@@ -122,7 +123,8 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||
wallpaperTargets, MODE_CLOSING);
|
||||
|
||||
// Use the top closing app to determine the insets for the animation
|
||||
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId);
|
||||
RemoteAnimationTargetCompat runningTaskTarget = mTargetTask == null ? null
|
||||
: targets.findTask(mTargetTask.taskId);
|
||||
if (runningTaskTarget == null) {
|
||||
Log.e(TAG, "No closing app");
|
||||
return pa.buildAnim();
|
||||
|
||||
@@ -38,7 +38,6 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI
|
||||
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
@@ -313,12 +312,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||
}
|
||||
|
||||
setupRecentsViewUi();
|
||||
|
||||
if (mDeviceState.getNavMode() == TWO_BUTTONS) {
|
||||
// If the device is in two button mode, swiping up will show overview with predictions
|
||||
// so we need to kick off switching to the overview predictions as soon as possible
|
||||
mActivityInterface.updateOverviewPredictionState();
|
||||
}
|
||||
linkRecentsViewScroll();
|
||||
|
||||
return true;
|
||||
@@ -423,7 +416,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||
}
|
||||
|
||||
protected void notifyGestureAnimationStartToRecents() {
|
||||
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
|
||||
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
|
||||
}
|
||||
|
||||
private void launcherFrameDrawn() {
|
||||
@@ -451,12 +444,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||
@Override
|
||||
public void onMotionPauseChanged(boolean isPaused) {
|
||||
setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
|
||||
|
||||
if (mDeviceState.isFullyGesturalNavMode() && isPaused) {
|
||||
// In fully gestural nav mode, switch to overview predictions once the user has paused
|
||||
// (this is a no-op if the predictions are already in that state)
|
||||
mActivityInterface.updateOverviewPredictionState();
|
||||
}
|
||||
}
|
||||
|
||||
public void maybeUpdateRecentsAttachedState() {
|
||||
@@ -555,14 +542,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||
|
||||
@Override
|
||||
public void updateFinalShift() {
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsAnimationTargets != null) {
|
||||
LiveTileOverlay.INSTANCE.update(
|
||||
mTaskViewSimulator.getCurrentCropRect(),
|
||||
mTaskViewSimulator.getCurrentCornerRadius());
|
||||
}
|
||||
}
|
||||
|
||||
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
|
||||
if (passed != mPassedOverviewThreshold) {
|
||||
mPassedOverviewThreshold = passed;
|
||||
@@ -573,6 +552,14 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||
|
||||
updateSysUiFlags(mCurrentShift.value);
|
||||
applyWindowTransform();
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsAnimationTargets != null) {
|
||||
LiveTileOverlay.INSTANCE.update(
|
||||
mTaskViewSimulator.getCurrentRect(),
|
||||
mTaskViewSimulator.getCurrentCornerRadius());
|
||||
}
|
||||
}
|
||||
|
||||
updateLauncherTransitionProgress();
|
||||
}
|
||||
|
||||
|
||||
-10
@@ -261,16 +261,6 @@ public final class LauncherActivityInterface extends
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOverviewPredictionState() {
|
||||
Launcher launcher = getCreatedActivity();
|
||||
if (launcher == null) {
|
||||
return;
|
||||
}
|
||||
PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
|
||||
PredictionUiStateManager.Client.OVERVIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerType() {
|
||||
final Launcher launcher = getVisibleLauncher();
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -165,7 +164,7 @@ public class OverviewCommandHelper {
|
||||
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
|
||||
mCreateTime = SystemClock.elapsedRealtime();
|
||||
mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface,
|
||||
RecentsModel.getRunningTaskId(), mDeviceState);
|
||||
ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);
|
||||
|
||||
// Preload the plan
|
||||
mRecentsModel.getTasks(null);
|
||||
@@ -227,10 +226,6 @@ public class OverviewCommandHelper {
|
||||
LauncherLogProto.ContainerType.TASKSWITCHER);
|
||||
mUserEventLogged = true;
|
||||
}
|
||||
|
||||
// Switch prediction client to overview
|
||||
PredictionUiStateManager.INSTANCE.get(activity).switchClient(
|
||||
PredictionUiStateManager.Client.OVERVIEW);
|
||||
return mAnimationProvider.onActivityReady(activity, wasVisible);
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -76,7 +76,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
|
||||
*/
|
||||
public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
|
||||
mHomeTaskInfo = homeTaskInfo;
|
||||
onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId);
|
||||
onGestureAnimationStart(homeTaskInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,14 +107,15 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAddDummyTaskView(int runningTaskId) {
|
||||
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId
|
||||
protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
|
||||
if (mHomeTaskInfo != null && runningTaskInfo != null &&
|
||||
mHomeTaskInfo.taskId == runningTaskInfo.taskId
|
||||
&& getTaskViewCount() == 0) {
|
||||
// Do not add a dummy task if we are running over home with empty recents, so that we
|
||||
// show the empty recents message instead of showing a dummy task and later removing it.
|
||||
return false;
|
||||
}
|
||||
return super.shouldAddDummyTaskView(runningTaskId);
|
||||
return super.shouldAddDummyTaskView(runningTaskInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-2
@@ -205,13 +205,15 @@ public class StaggeredWorkspaceAnim {
|
||||
ResourceProvider rp = DynamicResource.provider(v.getContext());
|
||||
float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
|
||||
float damping = rp.getFloat(R.dimen.staggered_damping_ratio);
|
||||
float endTransY = 0;
|
||||
float springVelocity = Math.abs(mVelocity) * Math.signum(endTransY - mSpringTransY);
|
||||
ValueAnimator springTransY = new SpringAnimationBuilder(v.getContext())
|
||||
.setStiffness(stiffness)
|
||||
.setDampingRatio(damping)
|
||||
.setMinimumVisibleChange(1f)
|
||||
.setStartValue(mSpringTransY)
|
||||
.setEndValue(0)
|
||||
.setStartVelocity(mVelocity)
|
||||
.setEndValue(endTransY)
|
||||
.setStartVelocity(springVelocity)
|
||||
.build(v, VIEW_TRANSLATE_Y);
|
||||
springTransY.setStartDelay(startDelay);
|
||||
springTransY.addListener(new AnimatorListenerAdapter() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.states.RotationHelper.deltaRotation;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
|
||||
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
|
||||
@@ -197,6 +198,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
return mTempRectF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current task bounds in the Launcher coordinate space.
|
||||
*/
|
||||
public RectF getCurrentRect() {
|
||||
RectF result = getCurrentCropRect();
|
||||
mMatrix.mapRect(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public RecentsOrientedState getOrientationState() {
|
||||
return mOrientationState;
|
||||
}
|
||||
@@ -295,6 +305,10 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
builder.withMatrix(mMatrix)
|
||||
.withWindowCrop(mTmpCropRect)
|
||||
.withCornerRadius(getCurrentCornerRadius());
|
||||
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
|
||||
builder.withRelativeLayerTo(params.getRecentsSurface(), Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.util.FloatProperty;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -58,6 +59,7 @@ public class TransformParams {
|
||||
private float mCornerRadius;
|
||||
private RemoteAnimationTargets mTargetSet;
|
||||
private SurfaceTransactionApplier mSyncTransactionApplier;
|
||||
private SurfaceControl mRecentsSurface;
|
||||
|
||||
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||
@@ -138,6 +140,8 @@ public class TransformParams {
|
||||
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
|
||||
RemoteAnimationTargets targets = mTargetSet;
|
||||
SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
|
||||
mRecentsSurface = getRecentsSurface(targets);
|
||||
|
||||
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
|
||||
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
|
||||
@@ -165,6 +169,20 @@ public class TransformParams {
|
||||
return surfaceParams;
|
||||
}
|
||||
|
||||
private static SurfaceControl getRecentsSurface(RemoteAnimationTargets targets) {
|
||||
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
|
||||
if (app.mode == targets.targetMode) {
|
||||
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS) {
|
||||
return app.leash.getSurfaceControl();
|
||||
}
|
||||
} else {
|
||||
return app.leash.getSurfaceControl();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Pubic getters so outside packages can read the values.
|
||||
|
||||
public float getProgress() {
|
||||
@@ -179,6 +197,10 @@ public class TransformParams {
|
||||
return mCornerRadius;
|
||||
}
|
||||
|
||||
public SurfaceControl getRecentsSurface() {
|
||||
return mRecentsSurface;
|
||||
}
|
||||
|
||||
public RemoteAnimationTargets getTargetSet() {
|
||||
return mTargetSet;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
@@ -42,8 +43,10 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.util.Themes;
|
||||
@@ -139,7 +142,12 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||
config.userControlled = false;
|
||||
AnimatorPlaybackController stateAnimationController =
|
||||
mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
|
||||
float maxAllAppsProgress = 0.15f;
|
||||
float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f;
|
||||
|
||||
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
|
||||
PendingAnimation allAppsAlpha = new PendingAnimation(config.duration);
|
||||
allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha);
|
||||
mAnimation.play(allAppsAlpha.buildAnim());
|
||||
|
||||
ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
|
||||
intro.setInterpolator(LINEAR);
|
||||
@@ -191,7 +199,8 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mAnimation = null;
|
||||
stateAnimationController.dispatchOnCancel();
|
||||
// Handles cancelling the animation used to hint towards All Apps.
|
||||
mLauncher.getStateManager().goToState(NORMAL, false);
|
||||
handleClose(false);
|
||||
}
|
||||
});
|
||||
|
||||
-5
@@ -41,8 +41,6 @@ import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.Hotseat;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
@@ -237,9 +235,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||
super.reset();
|
||||
|
||||
setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0);
|
||||
// We are moving to home or some other UI with no recents. Switch back to the home client,
|
||||
// the home predictions should have been updated when the activity was resumed.
|
||||
PredictionUiStateManager.INSTANCE.get(getContext()).switchClient(Client.HOME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,6 +56,7 @@ import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -135,6 +136,7 @@ import com.android.quickstep.util.TransformParams;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.LauncherEventUtil;
|
||||
@@ -147,7 +149,7 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* A list of recent tasks.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public abstract class RecentsView<T extends StatefulActivity> extends PagedView implements
|
||||
Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
|
||||
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
|
||||
@@ -1041,13 +1043,13 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
/**
|
||||
* Called when a gesture from an app is starting.
|
||||
*/
|
||||
public void onGestureAnimationStart(int runningTaskId) {
|
||||
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
|
||||
// This needs to be called before the other states are set since it can create the task view
|
||||
if (mOrientationState.setGestureActive(true)) {
|
||||
updateOrientationHandler();
|
||||
}
|
||||
|
||||
showCurrentTask(runningTaskId);
|
||||
showCurrentTask(runningTaskInfo);
|
||||
setEnableFreeScroll(false);
|
||||
setEnableDrawingLiveTile(false);
|
||||
setRunningTaskHidden(true);
|
||||
@@ -1127,8 +1129,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
/**
|
||||
* Returns true if we should add a dummy taskView for the running task id
|
||||
*/
|
||||
protected boolean shouldAddDummyTaskView(int runningTaskId) {
|
||||
return getTaskView(runningTaskId) == null;
|
||||
protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
|
||||
return runningTaskInfo != null && getTaskView(runningTaskInfo.taskId) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1137,8 +1139,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
* All subsequent calls to reload will keep the task as the first item until {@link #reset()}
|
||||
* is called. Also scrolls the view to this task.
|
||||
*/
|
||||
public void showCurrentTask(int runningTaskId) {
|
||||
if (shouldAddDummyTaskView(runningTaskId)) {
|
||||
public void showCurrentTask(RunningTaskInfo runningTaskInfo) {
|
||||
if (shouldAddDummyTaskView(runningTaskInfo)) {
|
||||
boolean wasEmpty = getChildCount() == 0;
|
||||
// Add an empty view for now until the task plan is loaded and applied
|
||||
final TaskView taskView = mTaskViewPool.getView();
|
||||
@@ -1148,10 +1150,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
}
|
||||
// The temporary running task is only used for the duration between the start of the
|
||||
// gesture and the task list is loaded and applied
|
||||
mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(),
|
||||
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
|
||||
false, true, false, false, new ActivityManager.TaskDescription(), 0,
|
||||
new ComponentName("", ""), false);
|
||||
mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false);
|
||||
taskView.bind(mTmpRunningTask, mOrientationState);
|
||||
|
||||
// Measure and layout immediately so that the scroll values is updated instantly
|
||||
@@ -1162,7 +1161,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
}
|
||||
|
||||
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
||||
setCurrentTask(runningTaskId);
|
||||
setCurrentTask(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
|
||||
setCurrentPage(getRunningTaskIndex());
|
||||
setRunningTaskViewShowScreenshot(false);
|
||||
setRunningTaskHidden(runningTaskTileHidden);
|
||||
@@ -1680,7 +1679,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||
: View.LAYOUT_DIRECTION_RTL);
|
||||
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
|
||||
mActivity.getDragLayer().recreateControllers();
|
||||
boolean isInLandscape = mOrientationState.getTouchRotation() != 0
|
||||
boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
|
||||
|| mOrientationState.getRecentsActivityRotation() != ROTATION_0;
|
||||
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
|
||||
!mOrientationState.canRecentsActivityRotate() && isInLandscape);
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
|
||||
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
|
||||
@@ -50,7 +51,7 @@ public class RecentsActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecets_showCurrentTask() {
|
||||
public void testRecents_showCurrentTask() {
|
||||
ActivityController<RecentsActivity> controller =
|
||||
Robolectric.buildActivity(RecentsActivity.class);
|
||||
|
||||
@@ -58,7 +59,10 @@ public class RecentsActivityTest {
|
||||
doLayout(activity);
|
||||
|
||||
FallbackRecentsView frv = activity.getOverviewPanel();
|
||||
frv.showCurrentTask(22);
|
||||
|
||||
RunningTaskInfo dummyTask = new RunningTaskInfo();
|
||||
dummyTask.taskId = 22;
|
||||
frv.showCurrentTask(dummyTask);
|
||||
doLayout(activity);
|
||||
|
||||
ThumbnailData thumbnailData = new ThumbnailData();
|
||||
|
||||
@@ -157,6 +157,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
@Override
|
||||
protected void onDeferredResumed() {
|
||||
super.onDeferredResumed();
|
||||
handlePendingActivityRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handlePendingActivityRequest() {
|
||||
super.handlePendingActivityRequest();
|
||||
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
|
||||
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
|
||||
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||
|
||||
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
|
||||
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
|
||||
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
|
||||
@@ -62,7 +60,6 @@ import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Pair;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -879,10 +876,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
}
|
||||
});
|
||||
} else {
|
||||
float velocityDpPerS = DynamicResource.provider(mLauncher)
|
||||
float velocityPxPerS = DynamicResource.provider(mLauncher)
|
||||
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
|
||||
float velocityPxPerS = TypedValue.applyDimension(COMPLEX_UNIT_DIP,
|
||||
velocityDpPerS, mLauncher.getResources().getDisplayMetrics());
|
||||
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false)
|
||||
.getAnimators());
|
||||
}
|
||||
|
||||
@@ -153,13 +153,6 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
|
||||
public abstract void onExitOverview(RecentsAnimationDeviceState deviceState,
|
||||
Runnable exitRunnable);
|
||||
|
||||
/**
|
||||
* Updates the prediction state to the overview state.
|
||||
*/
|
||||
public void updateOverviewPredictionState() {
|
||||
// By public overview predictions are not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
|
||||
*/
|
||||
|
||||
@@ -92,15 +92,6 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The task id of the running task, or -1 if there is no current running task.
|
||||
*/
|
||||
public static int getRunningTaskId() {
|
||||
ActivityManager.RunningTaskInfo runningTask =
|
||||
ActivityManagerWrapper.getInstance().getRunningTask();
|
||||
return runningTask != null ? runningTask.id : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the provided {@param changeId} is the latest recent tasks list id.
|
||||
*/
|
||||
@@ -140,7 +131,9 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
}
|
||||
|
||||
// Keep the cache up to date with the latest thumbnails
|
||||
int runningTaskId = RecentsModel.getRunningTaskId();
|
||||
ActivityManager.RunningTaskInfo runningTask =
|
||||
ActivityManagerWrapper.getInstance().getRunningTask();
|
||||
int runningTaskId = runningTask != null ? runningTask.id : -1;
|
||||
mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
|
||||
for (Task task : tasks) {
|
||||
if (task.key.id == runningTaskId) {
|
||||
|
||||
@@ -49,7 +49,7 @@ public class LayoutUtils {
|
||||
Rect taskSize = new Rect();
|
||||
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
|
||||
orientationHandler);
|
||||
return (dp.heightPx - taskSize.height()) / 2;
|
||||
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
|
||||
}
|
||||
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
|
||||
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false">
|
||||
|
||||
<com.android.launcher3.CellLayout
|
||||
android:id="@+id/workspace"
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
|
||||
<item name="staggered_stiffness" type="dimen" format="float">150</item>
|
||||
<dimen name="unlock_staggered_velocity_dp_per_s">3dp</dimen>
|
||||
<dimen name="unlock_staggered_velocity_dp_per_s">4dp</dimen>
|
||||
|
||||
<item name="hint_scale_damping_ratio" type="dimen" format="float">0.7</item>
|
||||
<item name="hint_scale_stiffness" type="dimen" format="float">200</item>
|
||||
|
||||
@@ -183,6 +183,10 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||
public void onScrollStateChanged(int state) {
|
||||
super.onScrollStateChanged(state);
|
||||
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onScrollStateChanged: " + state);
|
||||
}
|
||||
|
||||
if (state == SCROLL_STATE_IDLE) {
|
||||
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
||||
}
|
||||
@@ -192,6 +196,10 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
if (isLayoutSuppressed()) info.setScrollable(false);
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS,
|
||||
"onInitializeAccessibilityNodeInfo, scrollable: " + info.isScrollable());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,8 +207,12 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||
final boolean changing = frozen != isLayoutSuppressed();
|
||||
super.setLayoutFrozen(frozen);
|
||||
if (changing) {
|
||||
ActivityContext.lookupContext(getContext()).getDragLayer()
|
||||
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "setLayoutFrozen " + frozen
|
||||
+ " @ " + Log.getStackTraceString(new Throwable()));
|
||||
ActivityContext.lookupContext(getContext()).getDragLayer()
|
||||
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -923,6 +923,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
DiscoveryBounce.showForHomeIfNeeded(this);
|
||||
}
|
||||
|
||||
protected void handlePendingActivityRequest() { }
|
||||
|
||||
private void logStopAndResume(int command) {
|
||||
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
|
||||
@@ -1423,7 +1424,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
if (!isInState(NORMAL)) {
|
||||
// Only change state, if not already the same. This prevents cancelling any
|
||||
// animations running as part of resume
|
||||
mStateManager.goToState(NORMAL);
|
||||
mStateManager.goToState(NORMAL, mStateManager.shouldAnimateStateChange(),
|
||||
this::handlePendingActivityRequest);
|
||||
}
|
||||
|
||||
// Reset the apps view
|
||||
|
||||
@@ -58,7 +58,7 @@ import com.android.launcher3.pm.InstallSessionTracker;
|
||||
import com.android.launcher3.pm.PackageInstallInfo;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
@@ -410,7 +410,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
enqueueModelUpdateTask(new BaseModelUpdateTask() {
|
||||
@Override
|
||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||
final IntSparseArrayMap<Boolean> removedIds = new IntSparseArrayMap<>();
|
||||
final IntSet removedIds = new IntSet();
|
||||
synchronized (dataModel) {
|
||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo
|
||||
@@ -418,13 +418,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
&& user.equals(info.user)
|
||||
&& info.getIntent() != null
|
||||
&& TextUtils.equals(packageName, info.getIntent().getPackage())) {
|
||||
removedIds.put(info.id, true /* remove */);
|
||||
removedIds.add(info.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!removedIds.isEmpty()) {
|
||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false));
|
||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -250,7 +250,8 @@ public abstract class LauncherState implements BaseState<LauncherState> {
|
||||
}
|
||||
|
||||
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
||||
if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
|
||||
if ((this != NORMAL && this != HINT_STATE)
|
||||
|| !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
|
||||
return DEFAULT_ALPHA_PROVIDER;
|
||||
}
|
||||
final int centerPage = launcher.getWorkspace().getNextPage();
|
||||
|
||||
@@ -83,7 +83,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
protected final BaseDraggingActivity mLauncher;
|
||||
protected final AdapterHolder[] mAH;
|
||||
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
|
||||
private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
|
||||
private final ItemInfoMatcher mWorkMatcher = mPersonalMatcher.negate();
|
||||
private final AllAppsStore mAllAppsStore = new AllAppsStore();
|
||||
|
||||
private final Paint mNavBarScrimPaint;
|
||||
|
||||
@@ -75,6 +75,9 @@ public class AccessibilityManagerCompat {
|
||||
}
|
||||
|
||||
public static void sendScrollFinishedEventToTest(Context context) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendScrollFinishedEventToTest");
|
||||
}
|
||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||
if (accessibilityManager == null) return;
|
||||
|
||||
@@ -94,6 +97,9 @@ public class AccessibilityManagerCompat {
|
||||
AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
||||
e.setClassName(eventTag);
|
||||
e.setParcelableData(data);
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendEventToTest " + e);
|
||||
}
|
||||
accessibilityManager.sendAccessibilityEvent(e);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,9 +241,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mFolderName.setSelectAllOnFocus(true);
|
||||
mFolderName.setInputType(mFolderName.getInputType()
|
||||
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
|
||||
& ~InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
|
||||
mFolderName.forceDisableSuggestions(!FeatureFlags.FOLDER_NAME_SUGGEST.get());
|
||||
mFolderName.forceDisableSuggestions(true);
|
||||
|
||||
mFooter = findViewById(R.id.folder_footer);
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -348,6 +349,19 @@ public class BgDataModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted
|
||||
* items and dynamic/predicted items for the provided {@code userHandle}.
|
||||
* Note the call is not synchronized over the model, that should be handled by the called.
|
||||
*/
|
||||
public void forAllWorkspaceItemInfos(UserHandle userHandle, Consumer<WorkspaceItemInfo> op) {
|
||||
for (ItemInfo info : itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo && userHandle.equals(info.user)) {
|
||||
op.accept((WorkspaceItemInfo) info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
// If the launcher has permission to access deep shortcuts.
|
||||
int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0;
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.os.UserHandle;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -48,23 +47,18 @@ public class CacheDataUpdatedTask extends BaseModelUpdateTask {
|
||||
@Override
|
||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||
IconCache iconCache = app.getIconCache();
|
||||
|
||||
|
||||
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
|
||||
|
||||
synchronized (dataModel) {
|
||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||
&& isValidShortcut(si) && cn != null
|
||||
&& mPackages.contains(cn.getPackageName())) {
|
||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
||||
updatedShortcuts.add(si);
|
||||
}
|
||||
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||
&& isValidShortcut(si) && cn != null
|
||||
&& mPackages.contains(cn.getPackageName())) {
|
||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
||||
updatedShortcuts.add(si);
|
||||
}
|
||||
}
|
||||
});
|
||||
apps.updateIconsAndLabels(mPackages, mUser);
|
||||
}
|
||||
bindUpdatedWorkspaceItems(updatedShortcuts);
|
||||
|
||||
@@ -20,8 +20,6 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel.CallbackTask;
|
||||
import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.PromiseAppInfo;
|
||||
@@ -70,21 +68,18 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||
|
||||
synchronized (dataModel) {
|
||||
final HashSet<ItemInfo> updates = new HashSet<>();
|
||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (si.hasPromiseIconUi() && (cn != null)
|
||||
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
|
||||
si.setInstallProgress(mInstallInfo.progress);
|
||||
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
||||
// Mark this info as broken.
|
||||
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
|
||||
}
|
||||
updates.add(si);
|
||||
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (si.hasPromiseIconUi() && (cn != null)
|
||||
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
|
||||
si.setInstallProgress(mInstallInfo.progress);
|
||||
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
||||
// Mark this info as broken.
|
||||
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
|
||||
}
|
||||
updates.add(si);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (LauncherAppWidgetInfo widget : dataModel.appWidgets) {
|
||||
if (widget.providerName.getPackageName().equals(mInstallInfo.packageName)) {
|
||||
@@ -94,12 +89,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
scheduleCallbackTask(new CallbackTask() {
|
||||
@Override
|
||||
public void execute(Callbacks callbacks) {
|
||||
callbacks.bindRestoreItemsChange(updates);
|
||||
}
|
||||
});
|
||||
scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.util.FlagOp;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
@@ -92,9 +92,11 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
|
||||
final String[] packages = mPackages;
|
||||
final int N = packages.length;
|
||||
FlagOp flagOp = FlagOp.NO_OP;
|
||||
final FlagOp flagOp;
|
||||
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
|
||||
final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
|
||||
? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
|
||||
: ItemInfoMatcher.ofPackages(packageSet, mUser);
|
||||
final HashSet<ComponentName> removedComponents = new HashSet<>();
|
||||
|
||||
switch (mOp) {
|
||||
@@ -158,19 +160,22 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
flagOp = ums.isUserQuiet(mUser)
|
||||
? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
|
||||
: FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER);
|
||||
// We want to update all packages for this user.
|
||||
matcher = ItemInfoMatcher.ofUser(mUser);
|
||||
appsList.updateDisabledFlags(matcher, flagOp);
|
||||
|
||||
// We are not synchronizing here, as int operations are atomic
|
||||
appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
flagOp = FlagOp.NO_OP;
|
||||
break;
|
||||
}
|
||||
|
||||
bindApplicationsIfNeeded();
|
||||
|
||||
final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
|
||||
final IntSet removedShortcuts = new IntSet();
|
||||
// Shortcuts to keep even if the corresponding app was removed
|
||||
final IntSet forceKeepShortcuts = new IntSet();
|
||||
|
||||
// Update shortcut infos
|
||||
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
|
||||
@@ -180,118 +185,118 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
// For system apps, package manager send OP_UPDATE when an app is enabled.
|
||||
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
|
||||
synchronized (dataModel) {
|
||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
boolean infoUpdated = false;
|
||||
boolean shortcutUpdated = false;
|
||||
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||
|
||||
// Update shortcuts which use iconResource.
|
||||
if ((si.iconResource != null)
|
||||
&& packageSet.contains(si.iconResource.packageName)) {
|
||||
LauncherIcons li = LauncherIcons.obtain(context);
|
||||
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
|
||||
li.recycle();
|
||||
if (iconInfo != null) {
|
||||
si.bitmap = iconInfo;
|
||||
infoUpdated = true;
|
||||
boolean infoUpdated = false;
|
||||
boolean shortcutUpdated = false;
|
||||
|
||||
// Update shortcuts which use iconResource.
|
||||
if ((si.iconResource != null)
|
||||
&& packageSet.contains(si.iconResource.packageName)) {
|
||||
LauncherIcons li = LauncherIcons.obtain(context);
|
||||
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
|
||||
li.recycle();
|
||||
if (iconInfo != null) {
|
||||
si.bitmap = iconInfo;
|
||||
infoUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (cn != null && matcher.matches(si, cn)) {
|
||||
String packageName = cn.getPackageName();
|
||||
|
||||
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
|
||||
forceKeepShortcuts.add(si.id);
|
||||
if (mOp == OP_REMOVE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (cn != null && matcher.matches(si, cn)) {
|
||||
String packageName = cn.getPackageName();
|
||||
|
||||
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
|
||||
removedShortcuts.put(si.id, false);
|
||||
if (mOp == OP_REMOVE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (si.isPromise() && isNewApkAvailable) {
|
||||
boolean isTargetValid = true;
|
||||
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
List<ShortcutInfo> shortcut =
|
||||
new ShortcutRequest(context, mUser)
|
||||
.forPackage(cn.getPackageName(),
|
||||
si.getDeepShortcutId())
|
||||
.query(ShortcutRequest.PINNED);
|
||||
if (shortcut.isEmpty()) {
|
||||
isTargetValid = false;
|
||||
} else {
|
||||
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
|
||||
infoUpdated = true;
|
||||
}
|
||||
} else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
|
||||
isTargetValid = context.getSystemService(LauncherApps.class)
|
||||
.isActivityEnabled(cn, mUser);
|
||||
}
|
||||
if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
|
||||
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||
infoUpdated = true;
|
||||
} else if (si.hasPromiseIconUi()) {
|
||||
removedShortcuts.put(si.id, true);
|
||||
continue;
|
||||
}
|
||||
} else if (!isTargetValid) {
|
||||
removedShortcuts.put(si.id, true);
|
||||
FileLog.e(TAG, "Restored shortcut no longer valid "
|
||||
+ si.getIntent());
|
||||
continue;
|
||||
if (si.isPromise() && isNewApkAvailable) {
|
||||
boolean isTargetValid = true;
|
||||
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
List<ShortcutInfo> shortcut =
|
||||
new ShortcutRequest(context, mUser)
|
||||
.forPackage(cn.getPackageName(),
|
||||
si.getDeepShortcutId())
|
||||
.query(ShortcutRequest.PINNED);
|
||||
if (shortcut.isEmpty()) {
|
||||
isTargetValid = false;
|
||||
} else {
|
||||
si.status = WorkspaceItemInfo.DEFAULT;
|
||||
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
|
||||
infoUpdated = true;
|
||||
}
|
||||
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
|
||||
} else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
|
||||
isTargetValid = context.getSystemService(LauncherApps.class)
|
||||
.isActivityEnabled(cn, mUser);
|
||||
}
|
||||
if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
|
||||
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||
infoUpdated = true;
|
||||
} else if (si.hasPromiseIconUi()) {
|
||||
removedShortcuts.add(si.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewApkAvailable &&
|
||||
si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
|
||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
||||
} else if (!isTargetValid) {
|
||||
removedShortcuts.add(si.id);
|
||||
FileLog.e(TAG, "Restored shortcut no longer valid "
|
||||
+ si.getIntent());
|
||||
return;
|
||||
} else {
|
||||
si.status = WorkspaceItemInfo.DEFAULT;
|
||||
infoUpdated = true;
|
||||
}
|
||||
|
||||
int oldRuntimeFlags = si.runtimeStatusFlags;
|
||||
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
|
||||
if (si.runtimeStatusFlags != oldRuntimeFlags) {
|
||||
shortcutUpdated = true;
|
||||
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
|
||||
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||
infoUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoUpdated || shortcutUpdated) {
|
||||
updatedWorkspaceItems.add(si);
|
||||
if (isNewApkAvailable
|
||||
&& si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
|
||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
||||
infoUpdated = true;
|
||||
}
|
||||
if (infoUpdated) {
|
||||
getModelWriter().updateItemInDatabase(si);
|
||||
}
|
||||
} else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) {
|
||||
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
|
||||
if (mUser.equals(widgetInfo.user)
|
||||
&& widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
|
||||
&& packageSet.contains(widgetInfo.providerName.getPackageName())) {
|
||||
widgetInfo.restoreStatus &=
|
||||
~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY &
|
||||
~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
|
||||
|
||||
// adding this flag ensures that launcher shows 'click to setup'
|
||||
// if the widget has a config activity. In case there is no config
|
||||
// activity, it will be marked as 'restored' during bind.
|
||||
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
||||
|
||||
widgets.add(widgetInfo);
|
||||
getModelWriter().updateItemInDatabase(widgetInfo);
|
||||
int oldRuntimeFlags = si.runtimeStatusFlags;
|
||||
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
|
||||
if (si.runtimeStatusFlags != oldRuntimeFlags) {
|
||||
shortcutUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoUpdated || shortcutUpdated) {
|
||||
updatedWorkspaceItems.add(si);
|
||||
}
|
||||
if (infoUpdated && si.id != ItemInfo.NO_ID) {
|
||||
getModelWriter().updateItemInDatabase(si);
|
||||
}
|
||||
});
|
||||
|
||||
for (LauncherAppWidgetInfo widgetInfo : dataModel.appWidgets) {
|
||||
if (mUser.equals(widgetInfo.user)
|
||||
&& widgetInfo.hasRestoreFlag(
|
||||
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
|
||||
&& packageSet.contains(widgetInfo.providerName.getPackageName())) {
|
||||
widgetInfo.restoreStatus &=
|
||||
~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY
|
||||
& ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
|
||||
|
||||
// adding this flag ensures that launcher shows 'click to setup'
|
||||
// if the widget has a config activity. In case there is no config
|
||||
// activity, it will be marked as 'restored' during bind.
|
||||
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
||||
|
||||
widgets.add(widgetInfo);
|
||||
getModelWriter().updateItemInDatabase(widgetInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bindUpdatedWorkspaceItems(updatedWorkspaceItems);
|
||||
if (!removedShortcuts.isEmpty()) {
|
||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
|
||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts));
|
||||
}
|
||||
|
||||
if (!widgets.isEmpty()) {
|
||||
@@ -319,7 +324,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
|
||||
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
|
||||
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
|
||||
.and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
|
||||
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
|
||||
deleteAndBindComponentsRemoved(removeMatch);
|
||||
|
||||
// Remove any queued items from the install queue
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
@@ -58,14 +57,14 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
|
||||
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
|
||||
HashSet<String> allIds = new HashSet<>();
|
||||
|
||||
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
|
||||
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
|
||||
if (mPackageName.equals(si.getIntent().getPackage()) && si.user.equals(mUser)) {
|
||||
synchronized (dataModel) {
|
||||
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||
if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
|
||||
&& mPackageName.equals(si.getIntent().getPackage())) {
|
||||
keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
|
||||
allIds.add(si.getDeepShortcutId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
@@ -73,27 +72,27 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
|
||||
ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
||||
HashSet<ShortcutKey> removedKeys = new HashSet<>();
|
||||
|
||||
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
|
||||
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
|
||||
&& mUser.equals(itemInfo.user)) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
|
||||
if (mIsUserUnlocked) {
|
||||
ShortcutKey key = ShortcutKey.fromItemInfo(si);
|
||||
ShortcutInfo shortcut = pinnedShortcuts.get(key);
|
||||
// We couldn't verify the shortcut during loader. If its no longer available
|
||||
// (probably due to clear data), delete the workspace item as well
|
||||
if (shortcut == null) {
|
||||
removedKeys.add(key);
|
||||
continue;
|
||||
synchronized (dataModel) {
|
||||
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
if (mIsUserUnlocked) {
|
||||
ShortcutKey key = ShortcutKey.fromItemInfo(si);
|
||||
ShortcutInfo shortcut = pinnedShortcuts.get(key);
|
||||
// We couldn't verify the shortcut during loader. If its no longer available
|
||||
// (probably due to clear data), delete the workspace item as well
|
||||
if (shortcut == null) {
|
||||
removedKeys.add(key);
|
||||
return;
|
||||
}
|
||||
si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
|
||||
si.updateFromDeepShortcutInfo(shortcut, context);
|
||||
app.getIconCache().getShortcutIcon(si, shortcut);
|
||||
} else {
|
||||
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
|
||||
}
|
||||
si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
|
||||
si.updateFromDeepShortcutInfo(shortcut, context);
|
||||
app.getIconCache().getShortcutIcon(si, shortcut);
|
||||
} else {
|
||||
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
|
||||
updatedWorkspaceItemInfos.add(si);
|
||||
}
|
||||
updatedWorkspaceItemInfos.add(si);
|
||||
}
|
||||
});
|
||||
}
|
||||
bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
|
||||
if (!removedKeys.isEmpty()) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.launcher3.widget.WidgetsFullSheet;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
@@ -92,6 +93,11 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||
l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
|
||||
return getLauncherUIProperty(Bundle::putInt,
|
||||
l -> WidgetsFullSheet.getWidgetsView(l).getCurrentScrollY());
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_WINDOW_INSETS: {
|
||||
return getUIProperty(Bundle::putParcelable, a -> {
|
||||
WindowInsets insets = a.getWindow()
|
||||
|
||||
@@ -81,6 +81,7 @@ public final class TestProtocol {
|
||||
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
|
||||
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
|
||||
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
|
||||
public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
|
||||
public static final String REQUEST_WINDOW_INSETS = "window-insets";
|
||||
public static final String REQUEST_PID = "pid";
|
||||
public static final String REQUEST_TOTAL_PSS_KB = "total_pss";
|
||||
@@ -106,4 +107,5 @@ public final class TestProtocol {
|
||||
public static final String PAUSE_NOT_DETECTED = "b/139891609";
|
||||
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
|
||||
public static final String NO_SWIPE_TO_HOME = "b/158017601";
|
||||
public static final String NO_SCROLL_END_WIDGETS = "b/160238801";
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3.touch;
|
||||
|
||||
import static android.widget.ListPopupWindow.WRAP_CONTENT;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
|
||||
@@ -33,6 +34,7 @@ import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
@@ -260,4 +262,10 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||
}
|
||||
return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
@Override
|
||||
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||
return rect.left;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ public interface PagedOrientationHandler {
|
||||
int getTaskMenuWidth(View view);
|
||||
int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout);
|
||||
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp);
|
||||
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
|
||||
|
||||
/**
|
||||
* Maps the velocity from the coordinate plane of the foreground app to that
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.OverScroller;
|
||||
@@ -257,4 +258,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
||||
}
|
||||
return new ChildBounds(childWidth, childHeight, childRight, childTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||
return dp.heightPx - rect.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.android.launcher3.touch;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||
@@ -77,4 +79,9 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||
view.setTranslationX(0);
|
||||
view.setTranslationY(translation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||
return dp.widthPx - rect.right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +81,10 @@ public interface ItemInfoMatcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matcher which returns the opposite boolean value of the provided
|
||||
* {@param matcher}.
|
||||
* Returns a new matcher with returns the opposite value of this.
|
||||
*/
|
||||
static ItemInfoMatcher not(ItemInfoMatcher matcher) {
|
||||
return (info, cn) -> !matcher.matches(info, cn);
|
||||
default ItemInfoMatcher negate() {
|
||||
return (info, cn) -> !matches(info, cn);
|
||||
}
|
||||
|
||||
static ItemInfoMatcher ofUser(UserHandle user) {
|
||||
@@ -105,7 +104,10 @@ public interface ItemInfoMatcher {
|
||||
keys.contains(ShortcutKey.fromItemInfo(info));
|
||||
}
|
||||
|
||||
static ItemInfoMatcher ofItemIds(IntSparseArrayMap<Boolean> ids, Boolean matchDefault) {
|
||||
return (info, cn) -> ids.get(info.id, matchDefault);
|
||||
/**
|
||||
* Returns a matcher for items with provided ids
|
||||
*/
|
||||
static ItemInfoMatcher ofItemIds(IntSet ids) {
|
||||
return (info, cn) -> ids.contains(info.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class OnboardingPrefs<T extends Launcher> {
|
||||
|
||||
private static final Map<String, Integer> MAX_COUNTS;
|
||||
static {
|
||||
Map<String, Integer> maxCounts = new ArrayMap<>(3);
|
||||
Map<String, Integer> maxCounts = new ArrayMap<>(4);
|
||||
maxCounts.put(HOME_BOUNCE_COUNT, 3);
|
||||
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
|
||||
maxCounts.put(ALL_APPS_COUNT, 5);
|
||||
|
||||
@@ -292,6 +292,9 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "BaseDragLayer: " + ev);
|
||||
}
|
||||
switch (ev.getAction()) {
|
||||
case ACTION_DOWN: {
|
||||
if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.util.Log;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -32,8 +34,8 @@ import java.util.Iterator;
|
||||
* methods accordingly.
|
||||
*/
|
||||
public class WidgetsDiffReporter {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "WidgetsDiffReporter";
|
||||
private static final boolean DEBUG = Utilities.IS_RUNNING_IN_TEST_HARNESS; // b/160238801
|
||||
private static final String TAG = TestProtocol.NO_SCROLL_END_WIDGETS;
|
||||
|
||||
private final IconCache mIconCache;
|
||||
private final RecyclerView.Adapter mListener;
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
@@ -38,8 +39,10 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
import com.android.launcher3.views.TopRoundedCornerView;
|
||||
|
||||
@@ -68,6 +71,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsFullSheet: " + ev);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
public WidgetsFullSheet(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@@ -120,6 +120,9 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||
public int getCurrentScrollY() {
|
||||
// Skip early if widgets are not bound.
|
||||
if (isModelNotReady() || getChildCount() == 0) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "getCurrentScrollY: -1");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -128,6 +131,10 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||
int y = (child.getMeasuredHeight() * rowIndex);
|
||||
int offset = getLayoutManager().getDecoratedTop(child);
|
||||
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS,
|
||||
"getCurrentScrollY: " + (getPaddingTop() + y - offset));
|
||||
}
|
||||
return getPaddingTop() + y - offset;
|
||||
}
|
||||
|
||||
@@ -158,13 +165,23 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||
mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
|
||||
}
|
||||
if (mTouchDownOnScroller) {
|
||||
return mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
|
||||
final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 1 " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 2 false");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView.onTouchEvent");
|
||||
}
|
||||
if (mTouchDownOnScroller) {
|
||||
mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
|
||||
}
|
||||
@@ -172,5 +189,31 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onRequestDisallowInterceptTouchEvent "
|
||||
+ disallowIntercept);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
final boolean result = super.dispatchTouchEvent(ev);
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView: state: "
|
||||
+ getScrollState()
|
||||
+ " can scroll: " + getLayoutManager().canScrollVertically()
|
||||
+ " result: " + result
|
||||
+ " layout suppressed: " + isLayoutSuppressed()
|
||||
+ " event: " + ev);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNestedScroll() {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "stopNestedScroll");
|
||||
}
|
||||
super.stopNestedScroll();
|
||||
}
|
||||
}
|
||||
@@ -73,20 +73,12 @@ public class ActivityLeakTracker implements Application.ActivityLifecycleCallbac
|
||||
}
|
||||
|
||||
public boolean noLeakedActivities() {
|
||||
int liveActivities = 0;
|
||||
int destroyedActivities = 0;
|
||||
|
||||
for (Activity activity : mActivities.keySet()) {
|
||||
if (activity.isDestroyed()) {
|
||||
++destroyedActivities;
|
||||
} else {
|
||||
++liveActivities;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (liveActivities > 2) return false;
|
||||
|
||||
// It's OK to have 1 leaked activity if no active activities exist.
|
||||
return liveActivities == 0 ? destroyedActivities <= 1 : destroyedActivities == 0;
|
||||
return mActivities.size() <= 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,9 +635,11 @@ public final class LauncherInstrumentation {
|
||||
Parcelable executeAndWaitForEvent(Runnable command,
|
||||
UiAutomation.AccessibilityEventFilter eventFilter, Supplier<String> message) {
|
||||
try {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: before");
|
||||
final AccessibilityEvent event =
|
||||
mInstrumentation.getUiAutomation().executeAndWaitForEvent(
|
||||
command, eventFilter, WAIT_TIME_MS);
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: after");
|
||||
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
|
||||
final Parcelable parcelableData = event.getParcelableData();
|
||||
event.recycle();
|
||||
@@ -1094,7 +1096,10 @@ public final class LauncherInstrumentation {
|
||||
executeAndWaitForEvent(
|
||||
() -> linearGesture(
|
||||
startX, startY, endX, endY, steps, slowDown, GestureScope.INSIDE),
|
||||
event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
|
||||
event -> {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "scroll: received event: " + event);
|
||||
return TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName());
|
||||
},
|
||||
() -> "Didn't receive a scroll end message: " + startX + ", " + startY
|
||||
+ ", " + endX + ", " + endY);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ public class LogEventChecker {
|
||||
while (true) {
|
||||
rawEvents = mLauncher.getTestInfo(TestProtocol.REQUEST_GET_TEST_EVENTS)
|
||||
.getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
if (rawEvents == null) return null;
|
||||
|
||||
final int expectedCount = mExpectedEvents.entrySet()
|
||||
.stream().mapToInt(e -> e.getValue().size()).sum();
|
||||
if (rawEvents.size() >= expectedCount
|
||||
@@ -83,6 +85,7 @@ public class LogEventChecker {
|
||||
|
||||
String verify(long waitForExpectedCountMs, boolean successfulGesture) {
|
||||
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
|
||||
if (actualEvents == null) return "null event sequences because launcher likely died";
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
boolean hasMismatches = false;
|
||||
@@ -91,8 +94,7 @@ public class LogEventChecker {
|
||||
|
||||
List<String> actual = new ArrayList<>(actualEvents.getNonNull(sequence));
|
||||
final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
|
||||
hasMismatches = hasMismatches
|
||||
|| mismatchPosition != -1 && !ignoreMistatch(successfulGesture, sequence);
|
||||
hasMismatches = hasMismatches || mismatchPosition != -1;
|
||||
formatSequenceWithMismatch(
|
||||
sb,
|
||||
sequence,
|
||||
@@ -103,8 +105,7 @@ public class LogEventChecker {
|
||||
// Check for unexpected event sequences in the actual data.
|
||||
for (String actualNamedSequence : actualEvents.keySet()) {
|
||||
if (!mExpectedEvents.containsKey(actualNamedSequence)) {
|
||||
hasMismatches = hasMismatches
|
||||
|| !ignoreMistatch(successfulGesture, actualNamedSequence);
|
||||
hasMismatches = true;
|
||||
formatSequenceWithMismatch(
|
||||
sb,
|
||||
actualNamedSequence,
|
||||
@@ -117,13 +118,6 @@ public class LogEventChecker {
|
||||
return hasMismatches ? "mismatching events: " + sb.toString() : null;
|
||||
}
|
||||
|
||||
// Workaround for b/154157191
|
||||
private static boolean ignoreMistatch(boolean successfulGesture, String sequence) {
|
||||
// b/156287114
|
||||
return false;
|
||||
// return TestProtocol.SEQUENCE_TIS.equals(sequence) && successfulGesture;
|
||||
}
|
||||
|
||||
// If the list of actual events matches the list of expected events, returns -1, otherwise
|
||||
// the position of the mismatch.
|
||||
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation.GestureScope;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -90,6 +91,12 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer {
|
||||
return LauncherInstrumentation.ContainerType.WIDGETS;
|
||||
}
|
||||
|
||||
private int getWidgetsScroll() {
|
||||
return mLauncher.getTestInfo(
|
||||
TestProtocol.REQUEST_WIDGETS_SCROLL_Y)
|
||||
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
public Widget getWidget(String labelText) {
|
||||
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
|
||||
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
@@ -136,7 +143,13 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
|
||||
mLauncher.assertTrue("Too many attempts", ++i <= 40);
|
||||
final int scroll = getWidgetsScroll();
|
||||
mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0);
|
||||
final int newScroll = getWidgetsScroll();
|
||||
mLauncher.assertTrue(
|
||||
"Scrolled in a wrong direction in Widgets: from " + scroll + " to "
|
||||
+ newScroll, newScroll >= scroll);
|
||||
mLauncher.assertTrue("Unable to scroll to the widget", newScroll != scroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user