From 352c0035cb475688c14898e79129f88ac03759c0 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 7 Sep 2021 15:26:19 -0700 Subject: [PATCH 1/8] Adding Winscope Launcher trace artifact Bug: 197991109 Test: local runs Change-Id: I8fe718570e1400e97ea107bc25e169f39257ff43 --- .../launcher3/util/rule/FailureWatcher.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java index f9a9997e99..65aaa24527 100644 --- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java +++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java @@ -2,6 +2,7 @@ package com.android.launcher3.util.rule; import static androidx.test.InstrumentationRegistry.getInstrumentation; +import android.content.Context; import android.os.FileUtils; import android.os.ParcelFileDescriptor.AutoCloseInputStream; import android.util.Log; @@ -45,11 +46,30 @@ public class FailureWatcher extends TestWatcher { return new Statement() { @Override public void evaluate() throws Throwable { + boolean success = false; try { Log.d("b/196820244", "Before evaluate"); + mDevice.executeShellCommand("cmd statusbar tracing start"); FailureWatcher.super.apply(base, description).evaluate(); Log.d("b/196820244", "After evaluate"); + success = true; } finally { + // Save artifact for Launcher Winscope trace. + mDevice.executeShellCommand("cmd statusbar tracing stop"); + final Context nexusLauncherContext = + getInstrumentation().getTargetContext() + .createPackageContext("com.google.android.apps.nexuslauncher", + 0); + final File launcherTrace = + new File(nexusLauncherContext.getFilesDir(), "launcher_trace.pb"); + if (success) { + mDevice.executeShellCommand("rm " + launcherTrace); + } else { + mDevice.executeShellCommand("mv " + launcherTrace + " " + + diagFile(description, "LauncherWinscope", "pb")); + } + + // Detect touch events coming from physical screen. if (mLauncher.hadNontestEvents()) { throw new AssertionError( "Launcher received events not sent by the test. This may mean " From cc6a1d6584643b56d054e55828702de3c804b45f Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 9 Sep 2021 09:06:39 -0700 Subject: [PATCH 2/8] Fix taskbar education not touchable if taskbar is stashed Instead of assuming taskbar window is not touchable while taskbar is stashed, fall through to the areIconsVisible() check, which already returns false if taskbar is stashed anyway. Additionally, add a check for AbstractFloatingView so we appropriately allow touches if one exists. Test: Open Contacts, can still touch through stashed handle; start TaskbarEduView flow and can touch whether taskbar is stashed or not Fixes: 199376513 Change-Id: If362bad5cb8262fc8c489010e4b2d306ac5f252a --- .../launcher3/taskbar/LauncherTaskbarUIController.java | 2 +- .../launcher3/taskbar/TaskbarDragLayerController.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index b172095e96..0c22698b67 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -127,7 +127,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected boolean isTaskbarTouchable() { - return !isAnimatingToLauncher() && !mControllers.taskbarStashController.isStashed(); + return !isAnimatingToLauncher(); } private boolean isAnimatingToLauncher() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index b7c5db2f17..567a0c765a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -135,8 +135,9 @@ public class TaskbarDragLayerController { } else if (!mControllers.uiController.isTaskbarTouchable()) { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); - } else if (mControllers.taskbarViewController.areIconsVisible()) { - // Buttons are visible, take over the full taskbar area + } else if (mControllers.taskbarViewController.areIconsVisible() + || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null) { + // Taskbar has some touchable elements, take over the full taskbar area insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen() ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT); } else { From 5702b89b30cd451226b239022ba1b6c5c46873aa Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Fri, 10 Sep 2021 14:07:58 -0700 Subject: [PATCH 3/8] Base split action on focusedTaskView instead of runningTaskView * getRunningTaskView() is null when rotating device, only valid when swiping up to overview * focusedTaskView() correctly set in both cases Fixes: 199461147 Test: Bug doesn't repro Change-Id: Ib39c1f6f05b3cd5f72c13facc6b8000346896476 --- quickstep/src/com/android/quickstep/views/RecentsView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index dd470e87d0..3ed7b066fd 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3150,7 +3150,7 @@ public abstract class RecentsView 1 ); } From 4db4ec118b62f971be94b46b238270df0784ec96 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 10 Sep 2021 14:13:35 -0700 Subject: [PATCH 4/8] Destroy taskbar when device is shutting down Test: Shutdown/restart device, ensure taskbar isn't showing Fixes: 194633599 Change-Id: I8061e515e122c446438975b98527aeda6c59996a --- .../src/com/android/launcher3/taskbar/TaskbarManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 453bf1cabd..2e9d8bcd0c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -24,6 +24,7 @@ import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUN import android.content.ComponentCallbacks; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.hardware.display.DisplayManager; @@ -41,6 +42,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.SettingsCache; +import com.android.launcher3.util.SimpleBroadcastReceiver; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SystemUiProxy; @@ -62,6 +64,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen private final TaskbarNavButtonController mNavButtonController; private final SettingsCache.OnChangeListener mUserSetupCompleteListener; private final ComponentCallbacks mComponentCallbacks; + private final SimpleBroadcastReceiver mShutdownReceiver; // The source for this provider is set when Launcher is available private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider = @@ -103,12 +106,14 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen @Override public void onLowMemory() { } }; + mShutdownReceiver = new SimpleBroadcastReceiver(i -> destroyExistingTaskbar()); mDisplayController.addChangeListener(this); mSysUINavigationMode.addModeChangeListener(this); SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI, mUserSetupCompleteListener); mContext.registerComponentCallbacks(mComponentCallbacks); + mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN); recreateTaskbar(); } @@ -231,6 +236,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI, mUserSetupCompleteListener); mContext.unregisterComponentCallbacks(mComponentCallbacks); + mContext.unregisterReceiver(mShutdownReceiver); } public @Nullable TaskbarActivityContext getCurrentActivityContext() { From 57d4f748b89b2a07e2b33acdfdbcc3767df0aa41 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 6 Aug 2021 11:52:10 -0700 Subject: [PATCH 5/8] Fixing ModelPreload cancelling existing load When a model preload call was made while the loader task is running (eg: on enabling/disabling icon theme, Launcher reloads and then launcher preview start a model-preload), it would cancel the original loader and then start a new loader with empty callbacks. So the model indeed get loaded, but the original callbacks never got notified of it. > Instead we only start preload if an existing task is not running. > Also when preloading, we use existing callbacks, instead of using empty callbacks Bug: 193851085 Bug: 195155924 Test: Verified repro steps Change-Id: I0a96310be8489756f364aa2a12e4345e1418733d --- src/com/android/launcher3/LauncherModel.java | 33 ++++---- .../graphics/PreviewSurfaceRenderer.java | 18 ++--- .../android/launcher3/model/ModelPreload.java | 76 ------------------- 3 files changed, 22 insertions(+), 105 deletions(-) delete mode 100644 src/com/android/launcher3/model/ModelPreload.java diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index eef3980f96..545f4c3999 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -72,6 +72,7 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.function.Supplier; /** @@ -376,7 +377,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi loaderResults.bindWidgets(); return true; } else { - startLoaderForResults(loaderResults); + stopLoader(); + mLoaderTask = new LoaderTask( + mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults); + + // Always post the loader task, instead of running directly + // (even on same thread) so that we exit any nested synchronized blocks + MODEL_EXECUTOR.post(mLoaderTask); } } } @@ -399,25 +406,17 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi } } - public void startLoaderForResults(LoaderResults results) { + /** + * Loads the model if not loaded + * @param callback called with the data model upon successful load or null on model thread. + */ + public void loadAsync(Consumer callback) { synchronized (mLock) { - stopLoader(); - mLoaderTask = new LoaderTask( - mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, results); - - // Always post the loader task, instead of running directly (even on same thread) so - // that we exit any nested synchronized blocks - MODEL_EXECUTOR.post(mLoaderTask); - } - } - - public void startLoaderForResultsIfNotLoaded(LoaderResults results) { - synchronized (mLock) { - if (!isModelLoaded()) { - Log.d(TAG, "Workspace not loaded, loading now"); - startLoaderForResults(results); + if (!mModelLoaded && !mIsLoaderTaskRunning) { + startLoader(); } } + MODEL_EXECUTOR.post(() -> callback.accept(isModelLoaded() ? mBgDataModel : null)); } @Override diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index df493599ed..3b140a06bd 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -49,7 +49,6 @@ import com.android.launcher3.model.GridSizeMigrationTask; import com.android.launcher3.model.GridSizeMigrationTaskV2; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; -import com.android.launcher3.model.ModelPreload; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -174,18 +173,13 @@ public class PreviewSurfaceRenderer { } }.run(); } else { - new ModelPreload() { - - @Override - public void onComplete(boolean isSuccess) { - if (isSuccess) { - MAIN_EXECUTOR.execute(() -> - renderView(inflationContext, getBgDataModel(), null)); - } else { - Log.e(TAG, "Model loading failed"); - } + LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> { + if (dataModel != null) { + MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null)); + } else { + Log.e(TAG, "Model loading failed"); } - }.start(inflationContext); + }); } } diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java deleted file mode 100644 index 756b7da759..0000000000 --- a/src/com/android/launcher3/model/ModelPreload.java +++ /dev/null @@ -1,76 +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.launcher3.model; - -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; - -import android.content.Context; -import android.util.Log; - -import androidx.annotation.WorkerThread; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; -import com.android.launcher3.LauncherModel.ModelUpdateTask; -import com.android.launcher3.model.BgDataModel.Callbacks; - -import java.util.concurrent.Executor; - -/** - * Utility class to preload LauncherModel - */ -public class ModelPreload implements ModelUpdateTask { - - private static final String TAG = "ModelPreload"; - - private LauncherAppState mApp; - private LauncherModel mModel; - private BgDataModel mBgDataModel; - private AllAppsList mAllAppsList; - - @Override - public final void init(LauncherAppState app, LauncherModel model, BgDataModel dataModel, - AllAppsList allAppsList, Executor uiExecutor) { - mApp = app; - mModel = model; - mBgDataModel = dataModel; - mAllAppsList = allAppsList; - } - - @Override - public final void run() { - mModel.startLoaderForResultsIfNotLoaded( - new LoaderResults(mApp, mBgDataModel, mAllAppsList, new Callbacks[0])); - MODEL_EXECUTOR.post(() -> { - Log.d(TAG, "Preload completed : " + mModel.isModelLoaded()); - onComplete(mModel.isModelLoaded()); - }); - } - - public BgDataModel getBgDataModel() { - return mBgDataModel; - } - - /** - * Called when the task is complete - */ - @WorkerThread - public void onComplete(boolean isSuccess) { } - - public void start(Context context) { - LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(this); - } -} \ No newline at end of file From f66f8271cfe6bd4e9f2c1de8f907ef1b6291a3fa Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 13 Sep 2021 12:57:17 -0700 Subject: [PATCH 6/8] Use FakeTransformParams instead of real ones for gesture tutorial * SwipeUpAnimationLogic was ignoring the TransformParams arg that was being passed in, because for staged split we are creating/pairing TaskViewSimulators and TransformParams in SwipeUpAnimationLogic itself. * Override the remote handle that gets created during the gesture tutorial (which shouldn't be done in other cases, but because tutorial is a one-off it should be fine) Fixes: 199482330 Test: Launched gesture tutorial from launcher home settings No crash Change-Id: I346211a422e46981a994bd40e34e46b44f9f5d0e --- quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 2 +- .../src/com/android/quickstep/SwipeUpAnimationLogic.java | 2 +- .../interaction/SwipeUpGestureTutorialController.java | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 1e841da40b..fff89156cd 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -270,7 +270,7 @@ public abstract class AbsSwipeUpHandler, TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, InputConsumerController inputConsumer) { - super(context, deviceState, gestureState, new TransformParams()); + super(context, deviceState, gestureState); mActivityInterface = gestureState.getActivityInterface(); mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit); mInputConsumerProxy = diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index 51a491ebf6..e68af2e0a1 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -80,7 +80,7 @@ public abstract class SwipeUpAnimationLogic implements protected boolean mIsSwipeForStagedSplit; public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState, - GestureState gestureState, TransformParams transformParams) { + GestureState gestureState) { mContext = context; mDeviceState = deviceState; mGestureState = gestureState; diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java index 1f75936dd4..ce8047ec9e 100644 --- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java @@ -50,6 +50,7 @@ import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.RemoteTargetGluer; import com.android.quickstep.SwipeUpAnimationLogic; import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim; import com.android.quickstep.util.AppCloseConfig; @@ -254,7 +255,9 @@ abstract class SwipeUpGestureTutorialController extends TutorialController { ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState, GestureState gestureState) { - super(context, deviceState, gestureState, new FakeTransformParams()); + super(context, deviceState, gestureState); + mRemoteTargetHandles[0] = new RemoteTargetGluer.RemoteTargetHandle( + mRemoteTargetHandles[0].getTaskViewSimulator(), new FakeTransformParams()); } void initDp(DeviceProfile dp) { From 58030642b04061ca6a9899d61d9188a43e671663 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Sat, 4 Sep 2021 13:06:39 -0700 Subject: [PATCH 7/8] Add tmp buffer to rounded corners - Testing if this actually moves the gesture out of the screen decor area Bug: 197326121 Test: Pre/postsubmit Change-Id: I3c46ed3860ba6ba1fb605242b4f7242aaabc5672 --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 98d081b70a..ea8a295b83 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -1559,10 +1559,12 @@ public final class LauncherInstrumentation { } float getWindowCornerRadius() { + // TODO(b/197326121): Check if the touch is overlapping with the corners by offsetting + final float tmpBuffer = 100f; final Resources resources = getResources(); if (!supportsRoundedCornersOnWindows(resources)) { Log.d(TAG, "No rounded corners"); - return 0f; + return tmpBuffer; } // Radius that should be used in case top or bottom aren't defined. @@ -1581,7 +1583,7 @@ public final class LauncherInstrumentation { // Always use the smallest radius to make sure the rounded corners will // completely cover the display. Log.d(TAG, "Rounded corners top: " + topRadius + " bottom: " + bottomRadius); - return Math.max(topRadius, bottomRadius); + return Math.max(topRadius, bottomRadius) + tmpBuffer; } private static boolean supportsRoundedCornersOnWindows(Resources resources) { From e6abfca7ab99da1a0092cf812435402f1a01e788 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 13 Sep 2021 18:00:52 -0700 Subject: [PATCH 8/8] Set GroupedTaskView child thumbnails in onMeasure * Also add indicator if split was originally started in portrait of landscape, so we know which dimension of the divider bar to use if user goes to overview and then rotates device (horizontal divider vs vertical) Fixes: 199461137 Test: Swipe to overview with staged split Rotate device with and without live tile Doesn't overlap with overview actions Change-Id: I8b7f104f16d5b7265828f1b3d98ba3426b28d44f --- .../quickstep/views/GroupedTaskView.java | 30 +++++----- .../touch/LandscapePagedViewHandler.java | 32 ++++++---- .../touch/PagedOrientationHandler.java | 3 +- .../touch/PortraitPagedViewHandler.java | 58 +++++++++++-------- .../util/SplitConfigurationOptions.java | 10 +++- 5 files changed, 82 insertions(+), 51 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index 85627191c0..16303f3a02 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -31,6 +31,7 @@ public class GroupedTaskView extends TaskView { private Task mSecondaryTask; private TaskThumbnailView mSnapshotView2; private CancellableTask mThumbnailLoadRequest2; + private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig; public GroupedTaskView(Context context) { super(context); @@ -57,7 +58,7 @@ public class GroupedTaskView extends TaskView { mTaskIdContainer[1] = secondary.key.id; mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2); mSnapshotView2.bind(secondary); - adjustThumbnailBoundsForSplit(splitBoundsConfig, orientedState); + mSplitBoundsConfig = splitBoundsConfig; } @Override @@ -121,6 +122,21 @@ public class GroupedTaskView extends TaskView { public void onRecycle() { super.onRecycle(); mSnapshotView2.setThumbnail(mSecondaryTask, null); + mSplitBoundsConfig = null; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(widthSize, heightSize); + if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) { + return; + } + getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView, + mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig, + mActivity.getDeviceProfile()); } @Override @@ -128,16 +144,4 @@ public class GroupedTaskView extends TaskView { super.setOverlayEnabled(overlayEnabled); mSnapshotView2.setOverlayEnabled(overlayEnabled); } - - private void adjustThumbnailBoundsForSplit( - SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, - RecentsOrientedState orientedState) { - if (splitBoundsConfig == null) { - return; - } - - orientedState.getOrientationHandler().setGroupedTaskViewThumbnailBounds( - mSnapshotView, mSnapshotView2, this, splitBoundsConfig, - mActivity.getDeviceProfile()); - } } diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 895ca08510..2ac6cea636 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -408,22 +408,30 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { } @Override - public void setGroupedTaskViewThumbnailBounds(View mSnapshotView, View mSnapshotView2, - View taskParent, SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, - DeviceProfile dp) { + public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, + int parentWidth, int parentHeight, + SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; - int totalThumbnailHeight = taskParent.getHeight() - spaceAboveSnapshot; - int totalThumbnailWidth = taskParent.getWidth(); + int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; int dividerBar = splitBoundsConfig.visualDividerBounds.width(); - ViewGroup.LayoutParams primaryLp = mSnapshotView.getLayoutParams(); - ViewGroup.LayoutParams secondaryLp = mSnapshotView2.getLayoutParams(); + int primarySnapshotHeight; + int primarySnapshotWidth; + int secondarySnapshotHeight; + int secondarySnapshotWidth; - primaryLp.width = totalThumbnailWidth; - primaryLp.height = (int) (totalThumbnailHeight * splitBoundsConfig.leftTaskPercent); + primarySnapshotWidth = parentWidth; + primarySnapshotHeight = (int) (totalThumbnailHeight * splitBoundsConfig.leftTaskPercent); - secondaryLp.width = totalThumbnailWidth; - secondaryLp.height = totalThumbnailHeight - primaryLp.height - dividerBar; - mSnapshotView2.setTranslationY(primaryLp.height + spaceAboveSnapshot + dividerBar); + secondarySnapshotWidth = parentWidth; + secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar; + secondarySnapshot.setTranslationY(primarySnapshotHeight + spaceAboveSnapshot + dividerBar); + primarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY)); + secondarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight, + View.MeasureSpec.EXACTLY)); } @Override diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index b34a81eaa0..b119e2c0a9 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -162,7 +162,8 @@ public interface PagedOrientationHandler { SplitConfigurationOptions.StagedSplitBounds splitInfo, @SplitConfigurationOptions.StagePosition int desiredStagePosition); - void setGroupedTaskViewThumbnailBounds(View mSnapshot1, View mSnapshot2, View taskParent, + void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, + int parentWidth, int parentHeight, SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp); // Overview TaskMenuView methods diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 064d808756..e3fefc0284 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -35,7 +35,6 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.VelocityTracker; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.widget.LinearLayout; @@ -511,35 +510,46 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } @Override - public void setGroupedTaskViewThumbnailBounds(View mSnapshotView, View mSnapshotView2, - View taskParent, SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, - DeviceProfile dp) { + public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, + int parentWidth, int parentHeight, + SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; - int totalThumbnailHeight = taskParent.getHeight() - spaceAboveSnapshot; - int totalThumbnailWidth = taskParent.getWidth(); - int dividerBar = (dp.isLandscape ? - splitBoundsConfig.visualDividerBounds.width() : - splitBoundsConfig.visualDividerBounds.height()); - ViewGroup.LayoutParams primaryLp = mSnapshotView.getLayoutParams(); - ViewGroup.LayoutParams secondaryLp = mSnapshotView2.getLayoutParams(); - + int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; + int dividerBar = (splitBoundsConfig.appsStackedVertically ? + splitBoundsConfig.visualDividerBounds.height() : + splitBoundsConfig.visualDividerBounds.width()); + int primarySnapshotHeight; + int primarySnapshotWidth; + int secondarySnapshotHeight; + int secondarySnapshotWidth; + float taskPercent = splitBoundsConfig.appsStackedVertically ? + splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent; if (dp.isLandscape) { - primaryLp.height = totalThumbnailHeight; - primaryLp.width = (int) (totalThumbnailWidth * splitBoundsConfig.leftTaskPercent); + primarySnapshotHeight = totalThumbnailHeight; + primarySnapshotWidth = (int) (parentWidth * taskPercent); - secondaryLp.height = totalThumbnailHeight; - secondaryLp.width = totalThumbnailWidth - primaryLp.width - dividerBar; - mSnapshotView2.setTranslationX(primaryLp.width + dividerBar); - mSnapshotView2.setTranslationY(spaceAboveSnapshot); + secondarySnapshotHeight = totalThumbnailHeight; + secondarySnapshotWidth = parentWidth - primarySnapshotWidth - dividerBar; + int translationX = primarySnapshotWidth + dividerBar; + secondarySnapshot.setTranslationX(translationX); + secondarySnapshot.setTranslationY(spaceAboveSnapshot); } else { - primaryLp.width = totalThumbnailWidth; - primaryLp.height = (int) (totalThumbnailHeight * splitBoundsConfig.topTaskPercent); + primarySnapshotWidth = parentWidth; + primarySnapshotHeight = (int) (totalThumbnailHeight * taskPercent); - secondaryLp.width = totalThumbnailWidth; - secondaryLp.height = totalThumbnailHeight - primaryLp.height - dividerBar; - mSnapshotView2.setTranslationY(primaryLp.height + spaceAboveSnapshot + dividerBar); - mSnapshotView2.setTranslationX(0); + secondarySnapshotWidth = parentWidth; + secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar; + int translationY = primarySnapshotHeight + spaceAboveSnapshot + dividerBar; + secondarySnapshot.setTranslationY(translationY); + secondarySnapshot.setTranslationX(0); } + primarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY)); + secondarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight, + View.MeasureSpec.EXACTLY)); } @Override diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java index 5093d85535..0b083e3af4 100644 --- a/src/com/android/launcher3/util/SplitConfigurationOptions.java +++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java @@ -93,7 +93,13 @@ public final class SplitConfigurationOptions { // This class is orientation-agnostic, so we compute both for later use public final float topTaskPercent; public final float leftTaskPercent; - + /** + * If {@code true}, that means at the time of creation of this object, the + * split-screened apps were vertically stacked. This is useful in scenarios like + * rotation where the bounds won't change, but this variable can indicate what orientation + * the bounds were originally in + */ + public final boolean appsStackedVertically; public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds) { this.leftTopBounds = leftTopBounds; @@ -103,10 +109,12 @@ public final class SplitConfigurationOptions { // vertical apps, horizontal divider this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom, leftTopBounds.right, rightBottomBounds.top); + appsStackedVertically = true; } else { // horizontal apps, vertical divider this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top, rightBottomBounds.left, leftTopBounds.bottom); + appsStackedVertically = false; } leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;