Loading packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +51 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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(); Loading @@ -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) { Loading @@ -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, Loading Loading @@ -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(); Loading Loading @@ -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"); Loading packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +7 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); } Loading @@ -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) { Loading packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +157 −7 Original line number Diff line number Diff line Loading @@ -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 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 */); } @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 testDeliversAmbientModeChanged() { //TODO: We need add tests for GLEngine. 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 */); } // TODO: Add more test cases for GLEngine, tracing in b/124838911. 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); } } Loading
packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +51 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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(); Loading @@ -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) { Loading @@ -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, Loading Loading @@ -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(); Loading Loading @@ -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"); Loading
packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +7 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); } Loading @@ -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) { Loading
packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +157 −7 Original line number Diff line number Diff line Loading @@ -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 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 */); } @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 testDeliversAmbientModeChanged() { //TODO: We need add tests for GLEngine. 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 */); } // TODO: Add more test cases for GLEngine, tracing in b/124838911. 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); } }