Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78770959 authored by Roy Chou's avatar Roy Chou Committed by Android (Google) Code Review
Browse files

Merge "fix(window magnification): fix onSingleTap_enabled_scaleAnimates presubmit flaky" into main

parents e9fc0fb0 24043379
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -1461,8 +1461,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
        mDragView.setColorFilter(filter);
    }

    @VisibleForTesting
    void setBounceEffectDuration(int duration) {
    private void setBounceEffectDuration(int duration) {
        mBounceEffectDuration = duration;
    }

+0 −56
Original line number Diff line number Diff line
/*
 * 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.systemui.accessibility;

import android.os.RemoteException;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class MockMagnificationAnimationCallback extends IRemoteMagnificationAnimationCallback.Stub {

    private final CountDownLatch mCountDownLatch;
    private final AtomicInteger mSuccessCount;
    private final AtomicInteger mFailedCount;

    MockMagnificationAnimationCallback(CountDownLatch countDownLatch) {
        mCountDownLatch = countDownLatch;
        mSuccessCount = new AtomicInteger();
        mFailedCount = new AtomicInteger();
    }

    public int getSuccessCount() {
        return mSuccessCount.get();
    }

    public int getFailedCount() {
        return mFailedCount.get();
    }

    @Override
    public void onResult(boolean success) throws RemoteException {
        if (success) {
            mSuccessCount.getAndIncrement();
        } else {
            mFailedCount.getAndIncrement();
        }
        // It should be put at the last line to avoid making CountDownLatch#await passed without
        // updating values.
        mCountDownLatch.countDown();
    }
}
+63 −48
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -53,6 +54,7 @@ import static org.mockito.Mockito.when;

import android.animation.ValueAnimator;
import android.annotation.IdRes;
import android.annotation.Nullable;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -89,6 +91,7 @@ import androidx.test.filters.LargeTest;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.res.R;
import com.android.systemui.settings.FakeDisplayTracker;
@@ -102,6 +105,7 @@ import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -111,8 +115,6 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@LargeTest
@@ -120,12 +122,10 @@ import java.util.concurrent.atomic.AtomicInteger;
@RunWith(AndroidTestingRunner.class)
public class WindowMagnificationControllerTest extends SysuiTestCase {

    @Rule
    public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();

    private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
    // The duration couldn't too short, otherwise the animation check on bounce effect
    // won't work in expectation. (b/299537784)
    private static final int BOUNCE_EFFECT_DURATION_MS = 2000;
    private static final long ANIMATION_DURATION_MS = 300;
    private final long mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
    @Mock
    private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
    @Mock
@@ -134,11 +134,16 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
    private WindowMagnifierCallback mWindowMagnifierCallback;
    @Mock
    IRemoteMagnificationAnimationCallback mAnimationCallback;
    @Mock
    IRemoteMagnificationAnimationCallback mAnimationCallback2;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
    @Mock
    private SecureSettings mSecureSettings;

    private long mWaitAnimationDuration;
    private long mWaitBounceEffectDuration;

    private Handler mHandler;
    private TestableWindowManager mWindowManager;
    private SysUiState mSysUiState;
@@ -194,6 +199,13 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
            mResources.getConfiguration().orientation = ORIENTATION_PORTRAIT;
        }

        // Using the animation duration in WindowMagnificationAnimationController for testing.
        mWaitAnimationDuration = mResources.getInteger(
                com.android.internal.R.integer.config_longAnimTime);
        // Using the bounce effect duration in WindowMagnificationController for testing.
        mWaitBounceEffectDuration = mResources.getInteger(
                com.android.internal.R.integer.config_shortAnimTime);

        mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
                mContext, mValueAnimator);
        mWindowMagnificationController =
@@ -208,7 +220,6 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
                        mSysUiState,
                        () -> mWindowSessionSpy,
                        mSecureSettings);
        mWindowMagnificationController.setBounceEffectDuration(BOUNCE_EFFECT_DURATION_MS);

        verify(mMirrorWindowControl).setWindowDelegate(
                any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -281,9 +292,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
                    /* magnificationFrameOffsetRatioY= */ 0,
                    Mockito.mock(IRemoteMagnificationAnimationCallback.class));
        });
        advanceTimeBy(LAYOUT_CHANGE_TIMEOUT_MS);

        verify(mSfVsyncFrameProvider,
                timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeast(2)).postFrameCallback(any());
        verify(mSfVsyncFrameProvider, atLeast(2)).postFrameCallback(any());
    }

    @Test
@@ -401,14 +412,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {

    @Test
    public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
            throws InterruptedException {
            throws RemoteException {
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN, 0, 0, null);
        });
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        final MockMagnificationAnimationCallback animationCallback =
                new MockMagnificationAnimationCallback(countDownLatch);

        final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -417,12 +426,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {

        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.moveWindowMagnifierToPosition(
                    targetCenterX, targetCenterY, animationCallback);
                    targetCenterX, targetCenterY, mAnimationCallback);
        });
        advanceTimeBy(mWaitAnimationDuration);

        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
        assertEquals(1, animationCallback.getSuccessCount());
        assertEquals(0, animationCallback.getFailedCount());
        verify(mAnimationCallback, times(1)).onResult(eq(true));
        verify(mAnimationCallback, never()).onResult(eq(false));
        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
        assertEquals(mWindowMagnificationController.getCenterX(),
@@ -435,14 +444,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {

    @Test
    public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
            throws InterruptedException {
            throws RemoteException {
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN, 0, 0, null);
        });
        final CountDownLatch countDownLatch = new CountDownLatch(4);
        final MockMagnificationAnimationCallback animationCallback =
                new MockMagnificationAnimationCallback(countDownLatch);

        final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -451,20 +458,20 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {

        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.moveWindowMagnifierToPosition(
                    centerX + 10, centerY + 10, animationCallback);
                    centerX + 10, centerY + 10, mAnimationCallback);
            mWindowMagnificationController.moveWindowMagnifierToPosition(
                    centerX + 20, centerY + 20, animationCallback);
                    centerX + 20, centerY + 20, mAnimationCallback);
            mWindowMagnificationController.moveWindowMagnifierToPosition(
                    centerX + 30, centerY + 30, animationCallback);
                    centerX + 30, centerY + 30, mAnimationCallback);
            mWindowMagnificationController.moveWindowMagnifierToPosition(
                    centerX + 40, centerY + 40, animationCallback);
                    centerX + 40, centerY + 40, mAnimationCallback2);
        });
        advanceTimeBy(mWaitAnimationDuration);

        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
        // only the last one callback will return true
        assertEquals(1, animationCallback.getSuccessCount());
        verify(mAnimationCallback2).onResult(eq(true));
        // the others will return false
        assertEquals(3, animationCallback.getFailedCount());
        verify(mAnimationCallback, times(3)).onResult(eq(false));
        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
        assertEquals(mWindowMagnificationController.getCenterX(),
@@ -1078,27 +1085,16 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {

        final View mirrorView = mWindowManager.getAttachedView();

        final long timeout = SystemClock.uptimeMillis() + 5000;
        final AtomicDouble maxScaleX = new AtomicDouble();
        final Runnable onAnimationFrame = new Runnable() {
            @Override
            public void run() {
        advanceTimeBy(mWaitBounceEffectDuration, /* runnableOnEachRefresh= */ () -> {
            // For some reason the fancy way doesn't compile...
            // maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
            final double oldMax = maxScaleX.get();
            final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
            assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
        });

                if (SystemClock.uptimeMillis() < timeout) {
                    mirrorView.postOnAnimation(this);
                }
            }
        };
        mirrorView.postOnAnimation(onAnimationFrame);

        waitForIdleSync();

        ReferenceTestUtils.waitForCondition(() -> maxScaleX.get() > 1.0);
        assertTrue(maxScaleX.get() > 1.0);
    }

    @Test
@@ -1455,4 +1451,23 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
        return newRotation;
    }

    // advance time based on the device frame refresh rate
    private void advanceTimeBy(long timeDelta) {
        advanceTimeBy(timeDelta, /* runnableOnEachRefresh= */ null);
    }

    // advance time based on the device frame refresh rate, and trigger runnable on each refresh
    private void advanceTimeBy(long timeDelta, @Nullable Runnable runnableOnEachRefresh) {
        final float frameRate = mContext.getDisplay().getRefreshRate();
        final int timeSlot = (int) (1000 / frameRate);
        int round = (int) Math.ceil((double) timeDelta / timeSlot);
        for (; round >= 0; round--) {
            mInstrumentation.runOnMainSync(() -> {
                mAnimatorTestRule.advanceTimeBy(timeSlot);
                if (runnableOnEachRefresh != null) {
                    runnableOnEachRefresh.run();
                }
            });
        }
    }
}