Merge "Unit tests for wide color gamut of ImageWallpaper"
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6f1effd..5f74d2e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -598,7 +598,8 @@
* is not able to access the wallpaper.
*/
public Drawable getDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
@@ -829,7 +830,8 @@
* null pointer if these is none.
*/
public Drawable peekDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
@@ -853,7 +855,8 @@
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable getFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -869,7 +872,8 @@
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable peekFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -892,10 +896,11 @@
if (!shouldEnableWideColorGamut()) {
return false;
}
- Bitmap bitmap = sGlobals.peekWallpaperBitmap(mContext, false, which, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bitmap = sGlobals.peekWallpaperBitmap(mContext, false, which, cmProxy);
return bitmap != null && bitmap.getColorSpace() != null
&& bitmap.getColorSpace() != ColorSpace.get(ColorSpace.Named.SRGB)
- && mCmProxy.isSupportedColorSpace(bitmap.getColorSpace());
+ && cmProxy.isSupportedColorSpace(bitmap.getColorSpace());
}
/**
@@ -928,8 +933,8 @@
* @hide
*/
public Bitmap getBitmapAsUser(int userId, boolean hardware) {
- return sGlobals.peekWallpaperBitmap(
- mContext, true, FLAG_SYSTEM, userId, hardware, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy);
}
/**
@@ -2074,12 +2079,23 @@
}
/**
- * A private class to help Globals#getCurrentWallpaperLocked handle color management.
+ * Get the instance of {@link ColorManagementProxy}.
+ *
+ * @return instance of {@link ColorManagementProxy}.
+ * @hide
*/
- private static class ColorManagementProxy {
+ public ColorManagementProxy getColorManagementProxy() {
+ return mCmProxy;
+ }
+
+ /**
+ * A hidden class to help {@link Globals#getCurrentWallpaperLocked} handle color management.
+ * @hide
+ */
+ public static class ColorManagementProxy {
private final Set<ColorSpace> mSupportedColorSpaces = new HashSet<>();
- ColorManagementProxy(Context context) {
+ public ColorManagementProxy(@NonNull Context context) {
// Get a list of supported wide gamut color spaces.
Display display = context.getDisplay();
if (display != null) {
@@ -2087,9 +2103,14 @@
}
}
+ @NonNull
+ public Set<ColorSpace> getSupportedColorSpaces() {
+ return mSupportedColorSpaces;
+ }
+
boolean isSupportedColorSpace(ColorSpace colorSpace) {
return colorSpace != null && (colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)
- || mSupportedColorSpaces.contains(colorSpace));
+ || getSupportedColorSpaces().contains(colorSpace));
}
void doColorManagement(ImageDecoder decoder, ImageDecoder.ImageInfo info) {
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
index 657a308..11e215d 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
@@ -153,11 +153,11 @@
return true;
}
- private boolean checkExtensionCapability(String extName) {
+ boolean checkExtensionCapability(String extName) {
return mExts.contains(extName);
}
- private int getWcgCapability() {
+ int getWcgCapability() {
if (checkExtensionCapability(EXT_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH)) {
return EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
}
@@ -212,7 +212,7 @@
if (wcg && checkExtensionCapability(KHR_GL_COLOR_SPACE) && wcgCapability > 0) {
attrs = new int[] {EGL_GL_COLORSPACE_KHR, wcgCapability, EGL_NONE};
}
- mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, attrs, 0);
+ mEglSurface = askCreatingEglWindowSurface(surfaceHolder, attrs, 0 /* offset */);
} else {
Log.w(TAG, "Create EglSurface failed: hasEglDisplay=" + hasEglDisplay()
+ ", has valid surface=" + surfaceHolder.getSurface().isValid());
@@ -235,6 +235,10 @@
return true;
}
+ EGLSurface askCreatingEglWindowSurface(SurfaceHolder holder, int[] attrs, int offset) {
+ return eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, attrs, offset);
+ }
+
/**
* Destroy EglSurface.
*/
@@ -242,7 +246,7 @@
if (hasEglSurface()) {
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = null;
+ mEglSurface = EGL_NO_SURFACE;
}
}
@@ -296,7 +300,7 @@
public void destroyEglContext() {
if (hasEglContext()) {
eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = null;
+ mEglContext = EGL_NO_CONTEXT;
}
}
@@ -340,11 +344,16 @@
destroyEglContext();
}
if (hasEglDisplay()) {
- eglTerminate(mEglDisplay);
+ terminateEglDisplay();
}
mEglReady = false;
}
+ void terminateEglDisplay() {
+ eglTerminate(mEglDisplay);
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+
/**
* Called to dump current state.
* @param prefix prefix.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
index a5722e2..4b47093 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
@@ -16,52 +16,116 @@
package com.android.systemui.glwallpaper;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.RETURNS_DEFAULTS;
-import static org.mockito.Mockito.mock;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.PixelFormat;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
+import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceHolder;
+import android.view.SurfaceSession;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class EglHelperTest extends SysuiTestCase {
- @Mock
+ @Spy
private EglHelper mEglHelper;
+
@Mock
private SurfaceHolder mSurfaceHolder;
@Before
public void setUp() throws Exception {
- mEglHelper = mock(EglHelper.class, RETURNS_DEFAULTS);
- mSurfaceHolder = mock(SurfaceHolder.class, RETURNS_DEFAULTS);
+ MockitoAnnotations.initMocks(this);
+ prepareSurface();
+ }
+
+ @After
+ public void tearDown() {
+ mSurfaceHolder.getSurface().destroy();
+ mSurfaceHolder = null;
+ }
+
+ private void prepareSurface() {
+ final SurfaceSession session = new SurfaceSession();
+ final SurfaceControl control = new SurfaceControl.Builder(session)
+ .setName("Test")
+ .setBufferSize(100, 100)
+ .setFormat(PixelFormat.RGB_888)
+ .build();
+ final Surface surface = new Surface();
+ surface.copyFrom(control);
+ when(mSurfaceHolder.getSurface()).thenReturn(surface);
+ assertThat(mSurfaceHolder.getSurface()).isNotNull();
+ assertThat(mSurfaceHolder.getSurface().isValid()).isTrue();
}
@Test
public void testInit_finish() {
mEglHelper.init(mSurfaceHolder, false /* wideColorGamut */);
+ assertThat(mEglHelper.hasEglDisplay()).isTrue();
+ assertThat(mEglHelper.hasEglContext()).isTrue();
+ assertThat(mEglHelper.hasEglSurface()).isTrue();
+ verify(mEglHelper).askCreatingEglWindowSurface(
+ any(SurfaceHolder.class), eq(null), anyInt());
+
+ mEglHelper.finish();
+ assertThat(mEglHelper.hasEglSurface()).isFalse();
+ assertThat(mEglHelper.hasEglContext()).isFalse();
+ assertThat(mEglHelper.hasEglDisplay()).isFalse();
+ }
+
+ @Test
+ public void testInit_finish_wide_gamut() {
+ // In EglHelper, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
+ doReturn(0x3490).when(mEglHelper).getWcgCapability();
+ // In EglHelper, KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace";
+ doReturn(true).when(mEglHelper).checkExtensionCapability("EGL_KHR_gl_colorspace");
+ ArgumentCaptor<int[]> ac = ArgumentCaptor.forClass(int[].class);
+ // {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT, EGL_NONE}
+ final int[] expectedArgument = new int[] {0x309D, 0x3490, 0x3038};
+
+ mEglHelper.init(mSurfaceHolder, true /* wideColorGamut */);
+ verify(mEglHelper)
+ .askCreatingEglWindowSurface(any(SurfaceHolder.class), ac.capture(), anyInt());
+ assertThat(ac.getValue()).isNotNull();
+ assertThat(ac.getValue()).isEqualTo(expectedArgument);
mEglHelper.finish();
}
@Test
public void testFinish_shouldNotCrash() {
- assertFalse(mEglHelper.hasEglDisplay());
- assertFalse(mEglHelper.hasEglSurface());
- assertFalse(mEglHelper.hasEglContext());
+ mEglHelper.terminateEglDisplay();
+ assertThat(mEglHelper.hasEglDisplay()).isFalse();
+ assertThat(mEglHelper.hasEglSurface()).isFalse();
+ assertThat(mEglHelper.hasEglContext()).isFalse();
mEglHelper.finish();
+ verify(mEglHelper, never()).destroyEglContext();
+ verify(mEglHelper, never()).destroyEglSurface();
+ verify(mEglHelper, atMost(1)).terminateEglDisplay();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
new file mode 100644
index 0000000..d881fd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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.glwallpaper;
+
+import static com.android.systemui.glwallpaper.GLWallpaperRenderer.SurfaceProxy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.ColorManagementProxy;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class ImageWallpaperRendererTest extends SysuiTestCase {
+
+ private WallpaperManager mWpmSpy;
+ private SurfaceProxy mSurfaceProxy;
+
+ @Before
+ public void setUp() throws Exception {
+ final WallpaperManager wpm = mContext.getSystemService(WallpaperManager.class);
+ mWpmSpy = spy(wpm);
+ mContext.addMockSystemService(WallpaperManager.class, mWpmSpy);
+
+ mSurfaceProxy = new SurfaceProxy() {
+ @Override
+ public void requestRender() {
+ // NO-op
+ }
+
+ @Override
+ public void preRender() {
+ // No-op
+ }
+
+ @Override
+ public void postRender() {
+ // No-op
+ }
+ };
+ }
+
+ @Test
+ public void testWcgContent() throws IOException {
+ final Bitmap srgbBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ final Bitmap p3Bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888,
+ false /* hasAlpha */, ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+
+ final ColorManagementProxy proxy = new ColorManagementProxy(mContext);
+ final ColorManagementProxy cmProxySpy = spy(proxy);
+ final Set<ColorSpace> supportedWideGamuts = new HashSet<>();
+ supportedWideGamuts.add(ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+
+ try {
+ doReturn(true).when(mWpmSpy).shouldEnableWideColorGamut();
+ doReturn(cmProxySpy).when(mWpmSpy).getColorManagementProxy();
+ doReturn(supportedWideGamuts).when(cmProxySpy).getSupportedColorSpaces();
+
+ mWpmSpy.setBitmap(p3Bitmap);
+ ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
+ assertThat(rendererP3.isWcgContent()).isTrue();
+
+ mWpmSpy.setBitmap(srgbBitmap);
+ ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
+ assertThat(renderer.isWcgContent()).isFalse();
+ } finally {
+ srgbBitmap.recycle();
+ p3Bitmap.recycle();
+ }
+ }
+
+}