Merge "Add a new CanvasEngine, gated by flag" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fe97f28bed
@@ -16,12 +16,21 @@
|
||||
|
||||
package com.android.systemui.wallpapers;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static com.android.systemui.flags.Flags.USE_CANVAS_RENDERER;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.RecordingCanvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemClock;
|
||||
@@ -31,16 +40,22 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Size;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.wallpapers.canvas.ImageCanvasWallpaperRenderer;
|
||||
import com.android.systemui.wallpapers.gl.EglHelper;
|
||||
import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -59,16 +74,19 @@ public class ImageWallpaper extends WallpaperService {
|
||||
private static final @android.annotation.NonNull RectF LOCAL_COLOR_BOUNDS =
|
||||
new RectF(0, 0, 1, 1);
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final ArrayList<RectF> mLocalColorsToAdd = new ArrayList<>();
|
||||
private final ArraySet<RectF> mColorAreas = new ArraySet<>();
|
||||
private volatile int mPages = 1;
|
||||
private HandlerThread mWorker;
|
||||
// scaled down version
|
||||
private Bitmap mMiniBitmap;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
|
||||
@Inject
|
||||
public ImageWallpaper() {
|
||||
public ImageWallpaper(FeatureFlags featureFlags) {
|
||||
super();
|
||||
mFeatureFlags = featureFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,7 +98,7 @@ public class ImageWallpaper extends WallpaperService {
|
||||
|
||||
@Override
|
||||
public Engine onCreateEngine() {
|
||||
return new GLEngine();
|
||||
return mFeatureFlags.isEnabled(USE_CANVAS_RENDERER) ? new CanvasEngine() : new GLEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -489,4 +507,270 @@ public class ImageWallpaper extends WallpaperService {
|
||||
mRenderer.dump(prefix, fd, out, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CanvasEngine extends WallpaperService.Engine implements DisplayListener {
|
||||
|
||||
// time [ms] before unloading the wallpaper after it is loaded
|
||||
private static final int DELAY_FORGET_WALLPAPER = 5000;
|
||||
|
||||
private final Runnable mUnloadWallpaperCallback = this::unloadWallpaper;
|
||||
|
||||
private WallpaperManager mWallpaperManager;
|
||||
private ImageCanvasWallpaperRenderer mImageCanvasWallpaperRenderer;
|
||||
private Bitmap mBitmap;
|
||||
|
||||
private Display mDisplay;
|
||||
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
|
||||
|
||||
private AsyncTask<Void, Void, Bitmap> mLoader;
|
||||
private boolean mNeedsDrawAfterLoadingWallpaper = false;
|
||||
|
||||
CanvasEngine() {
|
||||
super();
|
||||
setFixedSizeAllowed(true);
|
||||
setShowForAllUsers(true);
|
||||
}
|
||||
|
||||
void trimMemory(int level) {
|
||||
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW
|
||||
&& level <= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL
|
||||
&& isBitmapLoaded()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "trimMemory");
|
||||
}
|
||||
unloadWallpaper();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SurfaceHolder surfaceHolder) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onCreate");
|
||||
}
|
||||
|
||||
mWallpaperManager = getSystemService(WallpaperManager.class);
|
||||
super.onCreate(surfaceHolder);
|
||||
|
||||
final Context displayContext = getDisplayContext();
|
||||
final int displayId = displayContext == null ? DEFAULT_DISPLAY :
|
||||
displayContext.getDisplayId();
|
||||
DisplayManager dm = getSystemService(DisplayManager.class);
|
||||
if (dm != null) {
|
||||
mDisplay = dm.getDisplay(displayId);
|
||||
if (mDisplay == null) {
|
||||
Log.e(TAG, "Cannot find display! Fallback to default.");
|
||||
mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
|
||||
}
|
||||
}
|
||||
setOffsetNotificationsEnabled(false);
|
||||
|
||||
mImageCanvasWallpaperRenderer = new ImageCanvasWallpaperRenderer(surfaceHolder);
|
||||
loadWallpaper(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
unloadWallpaper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldZoomOutWallpaper() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height);
|
||||
}
|
||||
super.onSurfaceChanged(holder, format, width, height);
|
||||
mImageCanvasWallpaperRenderer.setSurfaceHolder(holder);
|
||||
drawFrame(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceDestroyed(SurfaceHolder holder) {
|
||||
super.onSurfaceDestroyed(holder);
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "onSurfaceDestroyed");
|
||||
}
|
||||
mImageCanvasWallpaperRenderer.setSurfaceHolder(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(SurfaceHolder holder) {
|
||||
super.onSurfaceCreated(holder);
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "onSurfaceCreated");
|
||||
}
|
||||
mImageCanvasWallpaperRenderer.setSurfaceHolder(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onSurfaceRedrawNeeded");
|
||||
}
|
||||
super.onSurfaceRedrawNeeded(holder);
|
||||
// At the end of this method we should have drawn into the surface.
|
||||
// This means that the bitmap should be loaded synchronously if
|
||||
// it was already unloaded.
|
||||
if (!isBitmapLoaded()) {
|
||||
setBitmap(mWallpaperManager.getBitmap(true /* hardware */));
|
||||
}
|
||||
drawFrame(true);
|
||||
}
|
||||
|
||||
private DisplayInfo getDisplayInfo() {
|
||||
mDisplay.getDisplayInfo(mTmpDisplayInfo);
|
||||
return mTmpDisplayInfo;
|
||||
}
|
||||
|
||||
private void drawFrame(boolean forceRedraw) {
|
||||
if (!mImageCanvasWallpaperRenderer.isSurfaceHolderLoaded()) {
|
||||
Log.e(TAG, "attempt to draw a frame without a valid surface");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isBitmapLoaded()) {
|
||||
// ensure that we load the wallpaper.
|
||||
// if the wallpaper is currently loading, this call will have no effect.
|
||||
loadWallpaper(true);
|
||||
return;
|
||||
}
|
||||
mImageCanvasWallpaperRenderer.drawFrame(mBitmap, forceRedraw);
|
||||
}
|
||||
|
||||
private void setBitmap(Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
Log.e(TAG, "Attempt to set a null bitmap");
|
||||
} else if (mBitmap == bitmap) {
|
||||
Log.e(TAG, "The value of bitmap is the same");
|
||||
} else if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
|
||||
Log.e(TAG, "Attempt to set an invalid wallpaper of length "
|
||||
+ bitmap.getWidth() + "x" + bitmap.getHeight());
|
||||
} else {
|
||||
if (mBitmap != null) {
|
||||
mBitmap.recycle();
|
||||
}
|
||||
mBitmap = bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBitmapLoaded() {
|
||||
return mBitmap != null && !mBitmap.isRecycled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the wallpaper on background thread and schedules updating the surface frame,
|
||||
* and if {@code needsDraw} is set also draws a frame.
|
||||
*
|
||||
* If loading is already in-flight, subsequent loads are ignored (but needDraw is or-ed to
|
||||
* the active request).
|
||||
*
|
||||
*/
|
||||
private void loadWallpaper(boolean needsDraw) {
|
||||
mNeedsDrawAfterLoadingWallpaper |= needsDraw;
|
||||
if (mLoader != null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Skipping loadWallpaper, already in flight ");
|
||||
}
|
||||
return;
|
||||
}
|
||||
mLoader = new AsyncTask<Void, Void, Bitmap>() {
|
||||
@Override
|
||||
protected Bitmap doInBackground(Void... params) {
|
||||
Throwable exception;
|
||||
try {
|
||||
Bitmap wallpaper = mWallpaperManager.getBitmap(true /* hardware */);
|
||||
if (wallpaper != null
|
||||
&& wallpaper.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
|
||||
throw new RuntimeException("Wallpaper is too large to draw!");
|
||||
}
|
||||
return wallpaper;
|
||||
} catch (RuntimeException | OutOfMemoryError e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Note that if we do fail at this, and the default wallpaper can't
|
||||
// be loaded, we will go into a cycle. Don't do a build where the
|
||||
// default wallpaper can't be loaded.
|
||||
Log.w(TAG, "Unable to load wallpaper!", exception);
|
||||
try {
|
||||
mWallpaperManager.clear();
|
||||
} catch (IOException ex) {
|
||||
// now we're really screwed.
|
||||
Log.w(TAG, "Unable reset to default wallpaper!", ex);
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return mWallpaperManager.getBitmap(true /* hardware */);
|
||||
} catch (RuntimeException | OutOfMemoryError e) {
|
||||
Log.w(TAG, "Unable to load default wallpaper!", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
setBitmap(bitmap);
|
||||
|
||||
if (mNeedsDrawAfterLoadingWallpaper) {
|
||||
drawFrame(true);
|
||||
}
|
||||
|
||||
mLoader = null;
|
||||
mNeedsDrawAfterLoadingWallpaper = false;
|
||||
scheduleUnloadWallpaper();
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void unloadWallpaper() {
|
||||
if (mLoader != null) {
|
||||
mLoader.cancel(false);
|
||||
mLoader = null;
|
||||
}
|
||||
|
||||
if (mBitmap != null) {
|
||||
mBitmap.recycle();
|
||||
}
|
||||
mBitmap = null;
|
||||
|
||||
final Surface surface = getSurfaceHolder().getSurface();
|
||||
surface.hwuiDestroy();
|
||||
mWallpaperManager.forgetLoadedWallpaper();
|
||||
}
|
||||
|
||||
private void scheduleUnloadWallpaper() {
|
||||
Handler handler = getMainThreadHandler();
|
||||
handler.removeCallbacks(mUnloadWallpaperCallback);
|
||||
handler.postDelayed(mUnloadWallpaperCallback, DELAY_FORGET_WALLPAPER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.wallpapers.canvas;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Helper to draw a wallpaper on a surface.
|
||||
* It handles the geometry regarding the dimensions of the display and the wallpaper,
|
||||
* and rescales the surface and the wallpaper accordingly.
|
||||
*/
|
||||
public class ImageCanvasWallpaperRenderer {
|
||||
|
||||
private static final String TAG = ImageCanvasWallpaperRenderer.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private SurfaceHolder mSurfaceHolder;
|
||||
//private Bitmap mBitmap = null;
|
||||
|
||||
@VisibleForTesting
|
||||
static final int MIN_SURFACE_WIDTH = 128;
|
||||
@VisibleForTesting
|
||||
static final int MIN_SURFACE_HEIGHT = 128;
|
||||
|
||||
private boolean mSurfaceRedrawNeeded;
|
||||
|
||||
private int mLastSurfaceWidth = -1;
|
||||
private int mLastSurfaceHeight = -1;
|
||||
|
||||
public ImageCanvasWallpaperRenderer(SurfaceHolder surfaceHolder) {
|
||||
mSurfaceHolder = surfaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the surface holder on which to draw.
|
||||
* Should be called when the surface holder is created or changed
|
||||
* @param surfaceHolder the surface on which to draw the wallpaper
|
||||
*/
|
||||
public void setSurfaceHolder(SurfaceHolder surfaceHolder) {
|
||||
mSurfaceHolder = surfaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a surface holder is loaded
|
||||
* @return true if a valid surfaceHolder has been set.
|
||||
*/
|
||||
public boolean isSurfaceHolderLoaded() {
|
||||
return mSurfaceHolder != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and set the surface dimensions, by using the play and the bitmap dimensions.
|
||||
* The Bitmap must be loaded before any call to this function
|
||||
*/
|
||||
private boolean updateSurfaceSize(Bitmap bitmap) {
|
||||
int surfaceWidth = Math.max(MIN_SURFACE_WIDTH, bitmap.getWidth());
|
||||
int surfaceHeight = Math.max(MIN_SURFACE_HEIGHT, bitmap.getHeight());
|
||||
boolean surfaceChanged =
|
||||
surfaceWidth != mLastSurfaceWidth || surfaceHeight != mLastSurfaceHeight;
|
||||
if (surfaceChanged) {
|
||||
/*
|
||||
Used a fixed size surface, because we are special. We can do
|
||||
this because we know the current design of window animations doesn't
|
||||
cause this to break.
|
||||
*/
|
||||
mSurfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
|
||||
mLastSurfaceWidth = surfaceWidth;
|
||||
mLastSurfaceHeight = surfaceHeight;
|
||||
}
|
||||
return surfaceChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a the wallpaper on the surface.
|
||||
* The bitmap and the surface must be loaded before calling
|
||||
* this function.
|
||||
* @param forceRedraw redraw the wallpaper even if no changes are detected
|
||||
*/
|
||||
public void drawFrame(Bitmap bitmap, boolean forceRedraw) {
|
||||
|
||||
if (bitmap == null || bitmap.isRecycled()) {
|
||||
Log.e(TAG, "Attempt to draw frame before background is loaded:");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
|
||||
Log.e(TAG, "Attempt to set an invalid wallpaper of length "
|
||||
+ bitmap.getWidth() + "x" + bitmap.getHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
mSurfaceRedrawNeeded |= forceRedraw;
|
||||
boolean surfaceChanged = updateSurfaceSize(bitmap);
|
||||
|
||||
boolean redrawNeeded = surfaceChanged || mSurfaceRedrawNeeded;
|
||||
mSurfaceRedrawNeeded = false;
|
||||
|
||||
if (!redrawNeeded) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Suppressed drawFrame since redraw is not needed ");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Redrawing wallpaper");
|
||||
}
|
||||
drawWallpaperWithCanvas(bitmap);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void drawWallpaperWithCanvas(Bitmap bitmap) {
|
||||
Canvas c = mSurfaceHolder.lockHardwareCanvas();
|
||||
if (c != null) {
|
||||
Rect dest = mSurfaceHolder.getSurfaceFrame();
|
||||
Log.i(TAG, "Redrawing in rect: " + dest + " with surface size: "
|
||||
+ mLastSurfaceWidth + "x" + mLastSurfaceHeight);
|
||||
try {
|
||||
c.drawBitmap(bitmap, null, dest, null);
|
||||
} finally {
|
||||
mSurfaceHolder.unlockCanvasAndPost(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import android.view.DisplayInfo;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -72,6 +73,8 @@ public class ImageWallpaperTest extends SysuiTestCase {
|
||||
private Bitmap mWallpaperBitmap;
|
||||
@Mock
|
||||
private Handler mHandler;
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlags;
|
||||
|
||||
private CountDownLatch mEventCountdown;
|
||||
|
||||
@@ -100,7 +103,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private ImageWallpaper createImageWallpaper() {
|
||||
return new ImageWallpaper() {
|
||||
return new ImageWallpaper(mFeatureFlags) {
|
||||
@Override
|
||||
public Engine onCreateEngine() {
|
||||
return new GLEngine(mHandler) {
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.wallpapers.canvas;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.never;
|
||||
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 static org.mockito.hamcrest.MockitoHamcrest.intThat;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class ImageCanvasWallpaperRendererTest extends SysuiTestCase {
|
||||
|
||||
private static final int MOBILE_DISPLAY_WIDTH = 720;
|
||||
private static final int MOBILE_DISPLAY_HEIGHT = 1600;
|
||||
|
||||
@Mock
|
||||
private SurfaceHolder mMockSurfaceHolder;
|
||||
|
||||
@Mock
|
||||
private DisplayInfo mMockDisplayInfo;
|
||||
|
||||
@Mock
|
||||
private Bitmap mMockBitmap;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
allowTestableLooperAsMainThread();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
private void setDimensions(
|
||||
int bitmapWidth, int bitmapHeight,
|
||||
int displayWidth, int displayHeight) {
|
||||
when(mMockBitmap.getWidth()).thenReturn(bitmapWidth);
|
||||
when(mMockBitmap.getHeight()).thenReturn(bitmapHeight);
|
||||
mMockDisplayInfo.logicalWidth = displayWidth;
|
||||
mMockDisplayInfo.logicalHeight = displayHeight;
|
||||
}
|
||||
|
||||
private void testMinDimensions(
|
||||
int bitmapWidth, int bitmapHeight) {
|
||||
|
||||
clearInvocations(mMockSurfaceHolder);
|
||||
setDimensions(bitmapWidth, bitmapHeight,
|
||||
ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_WIDTH,
|
||||
ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_HEIGHT);
|
||||
|
||||
ImageCanvasWallpaperRenderer renderer =
|
||||
new ImageCanvasWallpaperRenderer(mMockSurfaceHolder);
|
||||
renderer.drawFrame(mMockBitmap, true);
|
||||
|
||||
verify(mMockSurfaceHolder, times(1)).setFixedSize(
|
||||
intThat(greaterThanOrEqualTo(ImageCanvasWallpaperRenderer.MIN_SURFACE_WIDTH)),
|
||||
intThat(greaterThanOrEqualTo(ImageCanvasWallpaperRenderer.MIN_SURFACE_HEIGHT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinSurface() {
|
||||
// test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
|
||||
testMinDimensions(8, 8);
|
||||
|
||||
testMinDimensions(100, 2000);
|
||||
|
||||
testMinDimensions(200, 1);
|
||||
}
|
||||
|
||||
private void testZeroDimensions(int bitmapWidth, int bitmapHeight) {
|
||||
|
||||
clearInvocations(mMockSurfaceHolder);
|
||||
setDimensions(bitmapWidth, bitmapHeight,
|
||||
ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_WIDTH,
|
||||
ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_HEIGHT);
|
||||
|
||||
ImageCanvasWallpaperRenderer renderer =
|
||||
new ImageCanvasWallpaperRenderer(mMockSurfaceHolder);
|
||||
ImageCanvasWallpaperRenderer spyRenderer = spy(renderer);
|
||||
spyRenderer.drawFrame(mMockBitmap, true);
|
||||
|
||||
verify(mMockSurfaceHolder, never()).setFixedSize(anyInt(), anyInt());
|
||||
verify(spyRenderer, never()).drawWallpaperWithCanvas(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroBitmap() {
|
||||
// test that updateSurfaceSize is not called with a bitmap of width 0 or height 0
|
||||
testZeroDimensions(
|
||||
0, 1
|
||||
);
|
||||
|
||||
testZeroDimensions(1, 0
|
||||
);
|
||||
|
||||
testZeroDimensions(0, 0
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user