diff options
3 files changed, 215 insertions, 30 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index e50d08c0cf9d..03bc738c8ab9 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -18,12 +18,14 @@ package com.android.systemui; import android.app.ActivityManager; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.HandlerThread; import android.os.Trace; import android.service.wallpaper.WallpaperService; import android.util.Log; import android.util.Size; +import android.view.DisplayInfo; import android.view.SurfaceHolder; import com.android.internal.annotations.VisibleForTesting; @@ -93,14 +95,20 @@ public class ImageWallpaper extends WallpaperService { private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; private final boolean mNeedTransition; + private boolean mShouldStopTransition; + @VisibleForTesting + final boolean mIsHighEndGfx; + private final boolean mDisplayNeedsBlanking; + private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Object mMonitor = new Object(); private boolean mNeedRedraw; // This variable can only be accessed in synchronized block. private boolean mWaitingForRendering; GLEngine(Context context, DozeParameters dozeParameters) { - mNeedTransition = ActivityManager.isHighEndGfx() - && !dozeParameters.getDisplayNeedsBlanking(); + mIsHighEndGfx = ActivityManager.isHighEndGfx(); + mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking(); + mNeedTransition = mIsHighEndGfx && !mDisplayNeedsBlanking; // We will preserve EGL context when we are in lock screen or aod // to avoid janking in following transition, we need to release when back to home. @@ -112,14 +120,23 @@ public class ImageWallpaper extends WallpaperService { @Override public void onCreate(SurfaceHolder surfaceHolder) { - mEglHelper = new EglHelper(); + mEglHelper = getEglHelperInstance(); // Deferred init renderer because we need to get wallpaper by display context. - mRenderer = new ImageWallpaperRenderer(getDisplayContext(), this /* SurfaceProxy */); + mRenderer = getRendererInstance(); + getDisplayContext().getDisplay().getDisplayInfo(mDisplayInfo); setFixedSizeAllowed(true); setOffsetNotificationsEnabled(true); updateSurfaceSize(); } + EglHelper getEglHelperInstance() { + return new EglHelper(); + } + + ImageWallpaperRenderer getRendererInstance() { + return new ImageWallpaperRenderer(getDisplayContext(), this /* SurfaceProxy */); + } + private void updateSurfaceSize() { SurfaceHolder holder = getSurfaceHolder(); Size frameSize = mRenderer.reportSurfaceSize(); @@ -128,6 +145,26 @@ public class ImageWallpaper extends WallpaperService { holder.setFixedSize(width, height); } + /** + * Check if necessary to stop transition with current wallpaper on this device. <br/> + * This should only be invoked after {@link #onSurfaceCreated(SurfaceHolder)}} + * is invoked since it needs display context and surface frame size. + * @return true if need to stop transition. + */ + @VisibleForTesting + boolean checkIfShouldStopTransition() { + int orientation = getDisplayContext().getResources().getConfiguration().orientation; + Rect frame = getSurfaceHolder().getSurfaceFrame(); + Rect display = new Rect(); + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + display.set(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + } else { + display.set(0, 0, mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth); + } + return mNeedTransition + && (frame.width() < display.width() || frame.height() < display.height()); + } + @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { @@ -137,12 +174,14 @@ public class ImageWallpaper extends WallpaperService { @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { if (!mNeedTransition) return; + final long duration = mShouldStopTransition ? 0 : animationDuration; if (DEBUG) { Log.d(TAG, "onAmbientModeChanged: inAmbient=" + inAmbientMode - + ", duration=" + animationDuration); + + ", duration=" + duration + + ", mShouldStopTransition=" + mShouldStopTransition); } mWorker.getThreadHandler().post( - () -> mRenderer.updateAmbientMode(inAmbientMode, animationDuration)); + () -> mRenderer.updateAmbientMode(inAmbientMode, duration)); if (inAmbientMode && animationDuration == 0) { // This means that we are transiting from home to aod, to avoid // race condition between window visibility and transition, @@ -183,6 +222,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceCreated(SurfaceHolder holder) { + mShouldStopTransition = checkIfShouldStopTransition(); mWorker.getThreadHandler().post(() -> { mEglHelper.init(holder, needSupportWideColorGamut()); mRenderer.onSurfaceCreated(); @@ -348,15 +388,13 @@ public class ImageWallpaper extends WallpaperService { protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { super.dump(prefix, fd, out, args); out.print(prefix); out.print("Engine="); out.println(this); - - boolean isHighEndGfx = ActivityManager.isHighEndGfx(); - out.print(prefix); out.print("isHighEndGfx="); out.println(isHighEndGfx); - + out.print(prefix); out.print("isHighEndGfx="); out.println(mIsHighEndGfx); out.print(prefix); out.print("displayNeedsBlanking="); - out.println( - mDozeParameters != null ? mDozeParameters.getDisplayNeedsBlanking() : "null"); - + out.println(mDisplayNeedsBlanking); + out.print(prefix); out.print("displayInfo="); out.print(mDisplayInfo); out.print(prefix); out.print("mNeedTransition="); out.println(mNeedTransition); + out.print(prefix); out.print("mShouldStopTransition="); + out.println(mShouldStopTransition); out.print(prefix); out.print("StatusBarState="); out.println(mController != null ? mController.getState() : "null"); diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index fa8269d1c198..ed6675dcba2e 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -31,7 +31,6 @@ import android.util.Log; import android.util.MathUtils; import android.util.Size; import android.view.DisplayInfo; -import android.view.WindowManager; import com.android.systemui.R; @@ -71,8 +70,7 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, } DisplayInfo displayInfo = new DisplayInfo(); - WindowManager wm = context.getSystemService(WindowManager.class); - wm.getDefaultDisplay().getDisplayInfo(displayInfo); + context.getDisplay().getDisplayInfo(displayInfo); // We only do transition in portrait currently, b/137962047. int orientation = context.getResources().getConfiguration().orientation; @@ -88,6 +86,10 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, mImageProcessHelper = new ImageProcessHelper(); mImageRevealHelper = new ImageRevealHelper(this); + startProcessingImage(); + } + + protected void startProcessingImage() { if (loadBitmap()) { // Compute threshold of the image, this is an async work. mImageProcessHelper.start(mBitmap); @@ -113,7 +115,7 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, mBitmap = null; } - private boolean loadBitmap() { + protected boolean loadBitmap() { if (DEBUG) { Log.d(TAG, "loadBitmap: mBitmap=" + mBitmap); } @@ -122,12 +124,7 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, mWcgContent = mWallpaperManager.wallpaperSupportsWcg(WallpaperManager.FLAG_SYSTEM); mWallpaperManager.forgetLoadedWallpaper(); if (mBitmap != null) { - float scale = (float) mScissor.height() / mBitmap.getHeight(); - int surfaceHeight = Math.max(mScissor.height(), mBitmap.getHeight()); - int surfaceWidth = scale > 1f - ? Math.round(mBitmap.getWidth() * scale) - : mBitmap.getWidth(); - mSurfaceSize.set(0, 0, surfaceWidth, surfaceHeight); + mSurfaceSize.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); } } if (DEBUG) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index 48a536924475..fc331d6adccc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -16,35 +16,185 @@ package com.android.systemui; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.WallpaperManager; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.ColorSpace; +import android.graphics.Rect; +import android.hardware.display.DisplayManagerGlobal; import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.Size; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.SurfaceHolder; -import androidx.test.runner.AndroidJUnit4; +import com.android.systemui.glwallpaper.ImageWallpaperRenderer; +import com.android.systemui.statusbar.phone.DozeParameters; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class ImageWallpaperTest extends SysuiTestCase { + private static final int LOW_BMP_WIDTH = 128; + private static final int LOW_BMP_HEIGHT = 128; + private static final int INVALID_BMP_WIDTH = 1; + private static final int INVALID_BMP_HEIGHT = 1; + private static final int DISPLAY_WIDTH = 1920; + private static final int DISPLAY_HEIGHT = 1080; + + @Mock + private SurfaceHolder mSurfaceHolder; + @Mock + private Context mMockContext; + @Mock + private Bitmap mWallpaperBitmap; + @Mock + private DozeParameters mDozeParam; private CountDownLatch mEventCountdown; - private CountDownLatch mAmbientEventCountdown; @Before public void setUp() throws Exception { + com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); MockitoAnnotations.initMocks(this); mEventCountdown = new CountDownLatch(1); - mAmbientEventCountdown = new CountDownLatch(2); + + WallpaperManager wallpaperManager = mock(WallpaperManager.class); + Resources resources = mock(Resources.class); + + when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(wallpaperManager); + when(mMockContext.getResources()).thenReturn(resources); + when(resources.getConfiguration()).thenReturn(mock(Configuration.class)); + + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = DISPLAY_WIDTH; + displayInfo.logicalHeight = DISPLAY_HEIGHT; + when(mMockContext.getDisplay()).thenReturn( + new Display(mock(DisplayManagerGlobal.class), 0, displayInfo, (Resources) null)); + + when(wallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap); + when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB)); + when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888); + when(mDozeParam.getDisplayNeedsBlanking()).thenReturn(false); + } + + private ImageWallpaper createImageWallpaper() { + return new ImageWallpaper(mDozeParam) { + @Override + public Engine onCreateEngine() { + return new GLEngine(mMockContext, mDozeParam) { + @Override + public Context getDisplayContext() { + return mMockContext; + } + + @Override + public SurfaceHolder getSurfaceHolder() { + return mSurfaceHolder; + } + + @Override + public void setFixedSizeAllowed(boolean allowed) { + super.setFixedSizeAllowed(allowed); + assertWithMessage("mFixedSizeAllowed should be true").that( + allowed).isTrue(); + mEventCountdown.countDown(); + } + }; + } + }; + } + + private ImageWallpaperRenderer createImageWallpaperRenderer(ImageWallpaper.GLEngine engine) { + return new ImageWallpaperRenderer(mMockContext, engine) { + @Override + public void startProcessingImage() { + loadBitmap(); + } + }; } @Test - public void testDeliversAmbientModeChanged() { - //TODO: We need add tests for GLEngine. + public void testBitmapWallpaper_normal() { + // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. + // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH. + // Finally, we assert the transition will not be stopped. + verifySurfaceSizeAndAssertTransition(DISPLAY_WIDTH /* bmpWidth */, + DISPLAY_WIDTH /* bmpHeight */, + DISPLAY_WIDTH /* surfaceWidth */, + DISPLAY_WIDTH /* surfaceHeight */, + false /* assertion */); } - // TODO: Add more test cases for GLEngine, tracing in b/124838911. + @Test + public void testBitmapWallpaper_low_resolution() { + // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. + // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT. + // Finally, we assert the transition will be stopped. + verifySurfaceSizeAndAssertTransition(LOW_BMP_WIDTH /* bmpWidth */, + LOW_BMP_HEIGHT /* bmpHeight */, + LOW_BMP_WIDTH /* surfaceWidth */, + LOW_BMP_HEIGHT /* surfaceHeight */, + true /* assertion */); + } + + @Test + public void testBitmapWallpaper_too_small() { + // Will use a image wallpaper with dimensions INVALID_BMP_WIDTH x INVALID_BMP_HEIGHT. + // Then we expect the surface size will be also MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT. + // Finally, we assert the transition will be stopped. + verifySurfaceSizeAndAssertTransition(INVALID_BMP_WIDTH /* bmpWidth */, + INVALID_BMP_HEIGHT /* bmpHeight */, + ImageWallpaper.GLEngine.MIN_SURFACE_WIDTH /* surfaceWidth */, + ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */, + true /* assertion */); + } + + private void verifySurfaceSizeAndAssertTransition(int bmpWidth, int bmpHeight, + int surfaceWidth, int surfaceHeight, boolean assertion) { + ImageWallpaper.GLEngine wallpaperEngine = + (ImageWallpaper.GLEngine) createImageWallpaper().onCreateEngine(); + + ImageWallpaper.GLEngine engineSpy = spy(wallpaperEngine); + when(engineSpy.mIsHighEndGfx).thenReturn(true); + + when(mWallpaperBitmap.getWidth()).thenReturn(bmpWidth); + when(mWallpaperBitmap.getHeight()).thenReturn(bmpHeight); + + ImageWallpaperRenderer renderer = createImageWallpaperRenderer(engineSpy); + doReturn(renderer).when(engineSpy).getRendererInstance(); + engineSpy.onCreate(engineSpy.getSurfaceHolder()); + + verify(mSurfaceHolder, times(1)).setFixedSize(surfaceWidth, surfaceHeight); + assertWithMessage("setFixedSizeAllowed should have been called.").that( + mEventCountdown.getCount()).isEqualTo(0); + + Size frameSize = renderer.reportSurfaceSize(); + Rect frame = new Rect(0, 0, frameSize.getWidth(), frameSize.getHeight()); + when(mSurfaceHolder.getSurfaceFrame()).thenReturn(frame); + + assertThat(engineSpy.checkIfShouldStopTransition()).isEqualTo(assertion); + } } |