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

Commit b4ab54ad authored by Wu Ahan's avatar Wu Ahan Committed by Android (Google) Code Review
Browse files

Merge "Unit tests for wide color gamut of ImageWallpaper"

parents 68021fb9 d8609336
Loading
Loading
Loading
Loading
+33 −12
Original line number Diff line number Diff line
@@ -598,7 +598,8 @@ public class WallpaperManager {
     *     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 @@ public class WallpaperManager {
     * 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 @@ public class WallpaperManager {
     */
    @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 @@ public class WallpaperManager {
     */
    @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 @@ public class WallpaperManager {
        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 @@ public class WallpaperManager {
     * @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 @@ public class WallpaperManager {
    }

    /**
     * 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 @@ public class WallpaperManager {
            }
        }

        @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) {
+15 −6
Original line number Diff line number Diff line
@@ -153,11 +153,11 @@ public class EglHelper {
        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 @@ public class EglHelper {
            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 @@ public class EglHelper {
        return true;
    }

    EGLSurface askCreatingEglWindowSurface(SurfaceHolder holder, int[] attrs, int offset) {
        return eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, attrs, offset);
    }

    /**
     * Destroy EglSurface.
     */
@@ -242,7 +246,7 @@ public class EglHelper {
        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 class EglHelper {
    public void destroyEglContext() {
        if (hasEglContext()) {
            eglDestroyContext(mEglDisplay, mEglContext);
            mEglContext = null;
            mEglContext = EGL_NO_CONTEXT;
        }
    }

@@ -340,11 +344,16 @@ public class EglHelper {
            destroyEglContext();
        }
        if (hasEglDisplay()) {
            eglTerminate(mEglDisplay);
            terminateEglDisplay();
        }
        mEglReady = false;
    }

    void terminateEglDisplay() {
        eglTerminate(mEglDisplay);
        mEglDisplay = EGL_NO_DISPLAY;
    }

    /**
     * Called to dump current state.
     * @param prefix prefix.
+76 −12
Original line number Diff line number Diff line
@@ -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();
    }
}
+106 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }

}