Re-map DisplayAreaAppearedInfo to token-leash map

Clean-up DA callback APIs of OneHandedDisplayAreaOrganizer
  onDisplayAreaAppeared()
  onDisplayAreaVanished()

Note:
  When super.unregisterOrganizer() is called, all DAs should be
  removed from the map in the callback of onDisplayAreaVanished().
  It was not working correctly because the map is using DisplayAreaInfo
  as the key, which will be different because of the different
  configuration object. We should use the DA token as the key.

Bug: b/172298357
Test: atest WMShellUnitTests:OneHandedDisplayAreaOrganizerTest
Test: atest SystemUITests
Test: Trigger OHM, rotate screen
Test: Trigger OHM, disabled through settings
Change-Id: I4560df1ab36ec33292fa4ec08cab28644b0fabe2
This commit is contained in:
Bill Lin
2020-11-03 16:26:00 +08:00
parent 2e4306e954
commit 1fd078151b
4 changed files with 57 additions and 60 deletions

View File

@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.window.WindowContainerToken;
import androidx.annotation.VisibleForTesting;
@@ -55,7 +56,7 @@ public class OneHandedAnimationController {
private final Interpolator mOvershootInterpolator;
private final OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private final HashMap<SurfaceControl, OneHandedTransitionAnimator> mAnimatorMap =
private final HashMap<WindowContainerToken, OneHandedTransitionAnimator> mAnimatorMap =
new HashMap<>();
/**
@@ -67,23 +68,23 @@ public class OneHandedAnimationController {
}
@SuppressWarnings("unchecked")
OneHandedTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds,
Rect endBounds) {
final OneHandedTransitionAnimator animator = mAnimatorMap.get(leash);
OneHandedTransitionAnimator getAnimator(WindowContainerToken token, SurfaceControl leash,
Rect startBounds, Rect endBounds) {
final OneHandedTransitionAnimator animator = mAnimatorMap.get(token);
if (animator == null) {
mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
mAnimatorMap.put(token, setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds)));
} else if (animator.isRunning()) {
animator.updateEndValue(endBounds);
} else {
animator.cancel();
mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
mAnimatorMap.put(token, setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds)));
}
return mAnimatorMap.get(leash);
return mAnimatorMap.get(token);
}
HashMap<SurfaceControl, OneHandedTransitionAnimator> getAnimatorMap() {
HashMap<WindowContainerToken, OneHandedTransitionAnimator> getAnimatorMap() {
return mAnimatorMap;
}
@@ -91,8 +92,8 @@ public class OneHandedAnimationController {
return mAnimatorMap.isEmpty();
}
void removeAnimator(SurfaceControl key) {
final OneHandedTransitionAnimator animator = mAnimatorMap.remove(key);
void removeAnimator(WindowContainerToken token) {
final OneHandedTransitionAnimator animator = mAnimatorMap.remove(token);
if (animator != null && animator.isRunning()) {
animator.cancel();
}
@@ -116,6 +117,7 @@ public class OneHandedAnimationController {
ValueAnimator.AnimatorListener {
private final SurfaceControl mLeash;
private final WindowContainerToken mToken;
private T mStartValue;
private T mEndValue;
private T mCurrentValue;
@@ -128,8 +130,10 @@ public class OneHandedAnimationController {
private @TransitionDirection int mTransitionDirection;
private OneHandedTransitionAnimator(SurfaceControl leash, T startValue, T endValue) {
private OneHandedTransitionAnimator(WindowContainerToken token, SurfaceControl leash,
T startValue, T endValue) {
mLeash = leash;
mToken = token;
mStartValue = startValue;
mEndValue = endValue;
addListener(this);
@@ -208,8 +212,8 @@ public class OneHandedAnimationController {
return this;
}
SurfaceControl getLeash() {
return mLeash;
WindowContainerToken getToken() {
return mToken;
}
Rect getDestinationBounds() {
@@ -254,10 +258,10 @@ public class OneHandedAnimationController {
}
@VisibleForTesting
static OneHandedTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
Rect startValue, Rect endValue) {
static OneHandedTransitionAnimator<Rect> ofBounds(WindowContainerToken token,
SurfaceControl leash, Rect startValue, Rect endValue) {
return new OneHandedTransitionAnimator<Rect>(leash, new Rect(startValue),
return new OneHandedTransitionAnimator<Rect>(token, leash, new Rect(startValue),
new Rect(endValue)) {
private final Rect mTmpRect = new Rect();

View File

@@ -26,11 +26,11 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -44,8 +44,6 @@ import com.android.wm.shell.common.ShellExecutor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* Manages OneHanded display areas such as offset.
@@ -69,7 +67,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
private int mEnterExitAnimationDurationMs;
@VisibleForTesting
ArrayMap<DisplayAreaInfo, SurfaceControl> mDisplayAreaMap = new ArrayMap();
ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaTokenMap = new ArrayMap();
private DisplayController mDisplayController;
private OneHandedAnimationController mAnimationController;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
@@ -89,7 +87,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
@Override
public void onOneHandedAnimationEnd(SurfaceControl.Transaction tx,
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
mAnimationController.removeAnimator(animator.getLeash());
mAnimationController.removeAnimator(animator.getToken());
if (mAnimationController.isAnimatorsConsumed()) {
finishOffset(animator.getDestinationOffset(),
animator.getTransitionDirection());
@@ -99,7 +97,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
@Override
public void onOneHandedAnimationCancel(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
mAnimationController.removeAnimator(animator.getLeash());
mAnimationController.removeAnimator(animator.getToken());
if (mAnimationController.isAnimatorsConsumed()) {
finishOffset(animator.getDestinationOffset(),
animator.getTransitionDirection());
@@ -119,7 +117,6 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
super(mainExecutor);
mAnimationController = animationController;
mDisplayController = displayController;
mDefaultDisplayBounds.set(getDisplayBounds());
mLastVisualDisplayBounds.set(getDisplayBounds());
final int animationDurationConfig = context.getResources().getInteger(
R.integer.config_one_handed_translate_animation_duration);
@@ -134,24 +131,12 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
@Override
public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
@NonNull SurfaceControl leash) {
Objects.requireNonNull(displayAreaInfo, "displayAreaInfo must not be null");
Objects.requireNonNull(leash, "leash must not be null");
if (mDisplayAreaMap.get(displayAreaInfo) == null) {
// mDefaultDisplayBounds may out of date after removeDisplayChangingController()
mDefaultDisplayBounds.set(getDisplayBounds());
mDisplayAreaMap.put(displayAreaInfo, leash);
}
mDisplayAreaTokenMap.put(displayAreaInfo.token, leash);
}
@Override
public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
Objects.requireNonNull(displayAreaInfo,
"Requires valid displayArea, and displayArea must not be null");
if (!mDisplayAreaMap.containsKey(displayAreaInfo)) {
Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
return;
}
mDisplayAreaMap.remove(displayAreaInfo);
mDisplayAreaTokenMap.remove(displayAreaInfo.token);
}
@Override
@@ -162,6 +147,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
}
mDefaultDisplayBounds.set(getDisplayBounds());
return displayAreaInfos;
}
@@ -176,9 +162,9 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
* handles 90 degree display rotation changes {@link Surface.Rotation}.
*
* @param fromRotation starting rotation of the display.
* @param toRotation target rotation of the display (after rotating).
* @param wct A task transaction {@link WindowContainerTransaction} from
* {@link DisplayChangeController} to populate.
* @param toRotation target rotation of the display (after rotating).
* @param wct A task transaction {@link WindowContainerTransaction} from
* {@link DisplayChangeController} to populate.
*/
public void onRotateDisplay(int fromRotation, int toRotation, WindowContainerTransaction wct) {
// Stop one handed without animation and reset cropped size immediately
@@ -210,11 +196,11 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
: TRANSITION_DIRECTION_EXIT;
final WindowContainerTransaction wct = new WindowContainerTransaction();
mDisplayAreaMap.forEach(
(key, leash) -> {
animateWindows(leash, fromBounds, toBounds, direction,
mDisplayAreaTokenMap.forEach(
(token, leash) -> {
animateWindows(token, leash, fromBounds, toBounds, direction,
mEnterExitAnimationDurationMs);
wct.setBounds(key.token, toBounds);
wct.setBounds(token, toBounds);
});
applyTransaction(wct);
}
@@ -222,10 +208,10 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
private void resetWindowsOffset(WindowContainerTransaction wct) {
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
mDisplayAreaMap.forEach(
(key, leash) -> {
mDisplayAreaTokenMap.forEach(
(token, leash) -> {
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
mAnimationController.getAnimatorMap().remove(leash);
mAnimationController.getAnimatorMap().remove(token);
if (animator != null && animator.isRunning()) {
animator.cancel();
}
@@ -233,16 +219,17 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
.setWindowCrop(leash, -1/* reset */, -1/* reset */);
// DisplayRotationController will applyTransaction() after finish rotating
if (wct != null) {
wct.setBounds(key.token, null/* reset */);
wct.setBounds(token, null/* reset */);
}
});
tx.apply();
}
private void animateWindows(SurfaceControl leash, Rect fromBounds, Rect toBounds,
@OneHandedAnimationController.TransitionDirection int direction, int durationMs) {
private void animateWindows(WindowContainerToken token, SurfaceControl leash, Rect fromBounds,
Rect toBounds, @OneHandedAnimationController.TransitionDirection int direction,
int durationMs) {
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
mAnimationController.getAnimator(leash, fromBounds, toBounds);
mAnimationController.getAnimator(token, leash, fromBounds, toBounds);
if (animator != null) {
animator.setTransitionDirection(direction)
.addOneHandedAnimationCallback(mOneHandedAnimationCallback)
@@ -311,8 +298,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mIsInOneHanded=");
pw.println(mIsInOneHanded);
pw.print(innerPrefix + "mDisplayAreaMap=");
pw.println(mDisplayAreaMap);
pw.print(innerPrefix + "mDisplayAreaTokenMap=");
pw.println(mDisplayAreaTokenMap);
pw.print(innerPrefix + "mDefaultDisplayBounds=");
pw.println(mDefaultDisplayBounds);
pw.print(innerPrefix + "mLastVisualDisplayBounds=");

View File

@@ -22,6 +22,7 @@ import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -50,6 +51,8 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
@Mock
private SurfaceControl mMockLeash;
@Mock
private WindowContainerToken mMockToken;
@Mock
private ShellExecutor mMainExecutor;
@@ -69,7 +72,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
destinationBounds.offset(0, 300);
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
mOneHandedAnimationController
.getAnimator(mMockLeash, originalBounds, destinationBounds);
.getAnimator(mMockToken, mMockLeash, originalBounds, destinationBounds);
assertNotNull(animator);
}

View File

@@ -24,13 +24,14 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.Binder;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
@@ -89,12 +90,14 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
Binder binder = new Binder();
doReturn(binder).when(mMockRealToken).asBinder();
mToken = new WindowContainerToken(mMockRealToken);
mLeash = new SurfaceControl();
mDisplay = mContext.getDisplay();
mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED);
mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
when(mMockAnimationController.getAnimator(any(), any(), any())).thenReturn(null);
when(mMockAnimationController.getAnimator(any(), any(), any(), any())).thenReturn(null);
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockSurfaceTransactionHelper.translate(any(), any(), anyFloat())).thenReturn(
mMockSurfaceTransactionHelper);
@@ -121,7 +124,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
public void testOnDisplayAreaAppeared() {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
verify(mMockAnimationController, never()).getAnimator(any(), any(), any());
verify(mMockAnimationController, never()).getAnimator(any(), any(), any(), any());
}
@Test
@@ -129,7 +132,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
mDisplayAreaOrganizer.onDisplayAreaVanished(mDisplayAreaInfo);
assertThat(mDisplayAreaOrganizer.mDisplayAreaMap).isEmpty();
assertThat(mDisplayAreaOrganizer.mDisplayAreaTokenMap).isEmpty();
}
@Test