Merge "Move PiP when it occludes a keep clear area with naive algorithm." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9e7f234b10
@@ -63,6 +63,7 @@ import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.pip.phone.PipAppOpsListener;
|
||||
import com.android.wm.shell.pip.phone.PipController;
|
||||
import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
|
||||
import com.android.wm.shell.pip.phone.PipMotionHelper;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.recents.RecentTasksController;
|
||||
@@ -207,7 +208,8 @@ public class WMShellModule {
|
||||
@Provides
|
||||
static Optional<Pip> providePip(Context context, DisplayController displayController,
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
|
||||
PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
@@ -215,9 +217,11 @@ public class WMShellModule {
|
||||
Optional<OneHandedController> oneHandedController,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return Optional.ofNullable(PipController.create(context, displayController,
|
||||
pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
|
||||
phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController,
|
||||
windowManagerShellWrapper, taskStackListener, oneHandedController, mainExecutor));
|
||||
pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
|
||||
pipMotionHelper,
|
||||
pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTouchHandler,
|
||||
pipTransitionController, windowManagerShellWrapper, taskStackListener,
|
||||
oneHandedController, mainExecutor));
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@@ -232,6 +236,12 @@ public class WMShellModule {
|
||||
return new PipSnapAlgorithm();
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
|
||||
return new PipKeepClearAlgorithm();
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
|
||||
|
||||
@@ -107,7 +107,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
private PipAppOpsListener mAppOpsListener;
|
||||
private PipMediaController mMediaController;
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private PipMotionHelper mPipMotionHelper;
|
||||
private PipTouchHandler mTouchHandler;
|
||||
private PipTransitionController mPipTransitionController;
|
||||
private TaskStackListenerImpl mTaskStackListener;
|
||||
@@ -241,6 +243,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
Set<Rect> unrestricted) {
|
||||
if (mPipBoundsState.getDisplayId() == displayId) {
|
||||
mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
|
||||
mPipMotionHelper.moveToBounds(mPipKeepClearAlgorithm.adjust(
|
||||
mPipBoundsState.getBounds(),
|
||||
mPipBoundsState.getRestrictedKeepClearAreas(),
|
||||
mPipBoundsState.getUnrestrictedKeepClearAreas()));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -293,7 +299,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
@Nullable
|
||||
public static Pip create(Context context, DisplayController displayController,
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
|
||||
PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
@@ -307,9 +314,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
}
|
||||
|
||||
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipMediaController, phonePipMenuController, pipTaskOrganizer,
|
||||
pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
|
||||
taskStackListener, oneHandedController, mainExecutor)
|
||||
pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
|
||||
phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController,
|
||||
windowManagerShellWrapper, taskStackListener, oneHandedController, mainExecutor)
|
||||
.mImpl;
|
||||
}
|
||||
|
||||
@@ -317,7 +324,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
DisplayController displayController,
|
||||
PipAppOpsListener pipAppOpsListener,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipKeepClearAlgorithm pipKeepClearAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
PipMediaController pipMediaController,
|
||||
PhonePipMenuController phonePipMenuController,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
@@ -339,7 +348,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
mWindowManagerShellWrapper = windowManagerShellWrapper;
|
||||
mDisplayController = displayController;
|
||||
mPipBoundsAlgorithm = pipBoundsAlgorithm;
|
||||
mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipMotionHelper = pipMotionHelper;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mMainExecutor = mainExecutor;
|
||||
mMediaController = pipMediaController;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.wm.shell.pip.phone;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Calculates the adjusted position that does not occlude keep clear areas.
|
||||
*/
|
||||
public class PipKeepClearAlgorithm {
|
||||
|
||||
/** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
|
||||
public Rect adjust(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
|
||||
Set<Rect> unrestrictedKeepClearAreas) {
|
||||
if (restrictedKeepClearAreas.isEmpty()) {
|
||||
return defaultBounds;
|
||||
}
|
||||
// TODO(b/183746978): implement the adjustment algorithm
|
||||
// naively check if areas intersect, an if so move PiP upwards
|
||||
Rect outBounds = new Rect(defaultBounds);
|
||||
for (Rect r : restrictedKeepClearAreas) {
|
||||
if (r.intersect(outBounds)) {
|
||||
outBounds.offset(0, r.top - outBounds.bottom);
|
||||
}
|
||||
}
|
||||
return outBounds;
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
@Mock private PhonePipMenuController mMockPhonePipMenuController;
|
||||
@Mock private PipAppOpsListener mMockPipAppOpsListener;
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
@Mock private PipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
|
||||
@Mock private PipSnapAlgorithm mMockPipSnapAlgorithm;
|
||||
@Mock private PipMediaController mMockPipMediaController;
|
||||
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
|
||||
@@ -97,9 +98,10 @@ public class PipControllerTest extends ShellTestCase {
|
||||
return null;
|
||||
}).when(mMockExecutor).execute(any());
|
||||
mPipController = new PipController(mContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
|
||||
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
|
||||
mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockTaskStackListener, mMockOneHandedController, mMockExecutor);
|
||||
when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
|
||||
when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
|
||||
@@ -128,9 +130,10 @@ public class PipControllerTest extends ShellTestCase {
|
||||
when(spyContext.getPackageManager()).thenReturn(mockPackageManager);
|
||||
|
||||
assertNull(PipController.create(spyContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
|
||||
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
|
||||
mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockTaskStackListener, mMockOneHandedController, mMockExecutor));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.wm.shell.pip.phone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Unit tests against {@link PipKeepClearAlgorithm}.
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class PipKeepClearAlgorithmTest extends ShellTestCase {
|
||||
|
||||
private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mPipKeepClearAlgorithm = new PipKeepClearAlgorithm();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withCollidingRestrictedKeepClearAreas_movesBounds() {
|
||||
final Rect inBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(50, 50, 150, 150);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
|
||||
Set.of());
|
||||
|
||||
assertFalse(outBounds.contains(keepClearRect));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withNonCollidingRestrictedKeepClearAreas_boundsDoNotChange() {
|
||||
final Rect inBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(100, 100, 150, 150);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
|
||||
Set.of());
|
||||
|
||||
assertEquals(inBounds, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
|
||||
// TODO(b/183746978): update this test to accommodate for the updated algorithm
|
||||
final Rect inBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(50, 50, 150, 150);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
|
||||
Set.of(keepClearRect));
|
||||
|
||||
assertEquals(inBounds, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withNonCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
|
||||
final Rect inBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(100, 100, 150, 150);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
|
||||
Set.of(keepClearRect));
|
||||
|
||||
assertEquals(inBounds, outBounds);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user