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

Commit a3468613 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11619294 from d0a4db8c to 24Q3-release

Change-Id: I336cf192d15a23010e315722999ecad0f526ecc1
parents e9c6c481 d0a4db8c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
// limitations under the License.
buildscript {
    ext.versions = [
            'gradle'       : '7.4.2',
            'gradle'       : '8.1.0',
            'minSdk'       : 34,
            'targetSdk'    : 34,
            'compileSdk'   : 34,
@@ -56,6 +56,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'org.jetbrains.kotlin.kapt'

android {
    namespace 'com.google.android.wallpaper.weathereffects'
    compileSdk versions.compileSdk

    defaultConfig {
+23 −0
Original line number Diff line number Diff line
@@ -19,6 +19,11 @@ android {
            java.srcDirs = ["${rootDir}/graphics/src"]
            assets.srcDirs = ["${rootDir}/graphics/assets"]
        }

        androidTest {
            java.srcDirs = ["${rootDir}/graphics/tests/src"]
            res.srcDirs = ["${rootDir}/graphics/tests/res"]
        }
    }

    buildTypes {
@@ -42,10 +47,28 @@ android {
    kotlinOptions {
        jvmTarget = '17'
    }

    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.11.0'

    androidTestImplementation "junit:junit:4.13.2"
    androidTestImplementation "androidx.test:core:1.5.0"
    androidTestImplementation "androidx.test:rules:1.5.0"
    androidTestImplementation "androidx.test:runner:1.5.2"
    androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5'
    androidTestImplementation "com.google.truth:truth:1.1.3"
    androidTestImplementation "org.mockito:mockito-core:5.10.0"
    androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.3"
    androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline-extended:2.28.3"
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"
}
+12 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.RecordingCanvas
import android.graphics.RenderEffect
import android.graphics.RenderNode
import android.hardware.HardwareBuffer
import androidx.annotation.VisibleForTesting
import java.time.Duration
import java.util.concurrent.Executor
import java.util.concurrent.Executors
@@ -49,7 +50,7 @@ class FrameBuffer(width: Int, height: Int, format: Int = HardwareBuffer.RGBA_888
        }

    private val executor = Executors.newFixedThreadPool(/* nThreads = */ 1)
    private val colorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
    @VisibleForTesting val colorSpace = ColorSpace.get(ColorSpace.Named.SRGB)

    /**
     * Recording drawing commands.
@@ -81,15 +82,18 @@ class FrameBuffer(width: Int, height: Int, format: Int = HardwareBuffer.RGBA_888
     *   executor.
     */
    fun tryObtainingImage(onImageReady: (image: Bitmap) -> Unit, callbackExecutor: Executor) {
        if (renderer.isClosed) return
        renderer.obtainRenderRequest().setColorSpace(colorSpace).draw(executor) { result ->
            if (result.status == HardwareBufferRenderer.RenderResult.SUCCESS) {
                result.fence.await(Duration.ofMillis(3000))
                result.fence.await(Duration.ofMillis(RESULT_FENCE_TIME_OUT))
                if (!buffer.isClosed) {
                    Bitmap.wrapHardwareBuffer(buffer, colorSpace)?.let {
                        callbackExecutor.execute { onImageReady.invoke(it) }
                    }
                }
            }
        }
    }

    /**
     * Configure the [FrameBuffer] to apply to this RenderNode. This will apply a visual effect to
@@ -99,4 +103,8 @@ class FrameBuffer(width: Int, height: Int, format: Int = HardwareBuffer.RGBA_888
     *   configured RenderEffects.
     */
    fun setRenderEffect(renderEffect: RenderEffect?) = node.setRenderEffect(renderEffect)

    companion object {
        const val RESULT_FENCE_TIME_OUT = 3000L
    }
}
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.google.android.wallpaper.weathereffects.graphics

import android.graphics.Bitmap
import android.graphics.Color
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.android.wallpaper.weathereffects.graphics.FrameBuffer.Companion.RESULT_FENCE_TIME_OUT
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class FrameBufferTest {

    private val executor = MoreExecutors.directExecutor()

    @Test
    fun onImageReady_invokesCallback() {
        val expectedWidth = 1
        val expectedHeight = 1
        val expectedColor = Color.RED

        val buffer = FrameBuffer(expectedWidth, expectedHeight)
        buffer.beginDrawing().drawColor(expectedColor)
        buffer.endDrawing()

        val latch = CountDownLatch(1)
        var bitmap: Bitmap? = null

        buffer.tryObtainingImage(
            {
                bitmap = it
                latch.countDown()
            },
            executor
        )

        assertThat(latch.await(RESULT_FENCE_TIME_OUT, TimeUnit.MILLISECONDS)).isTrue()

        assertThat(bitmap).isNotNull()
        val resultBitmap = bitmap!!
        assertThat(resultBitmap.width).isEqualTo(expectedWidth)
        assertThat(resultBitmap.height).isEqualTo(expectedHeight)
        assertThat(resultBitmap.colorSpace).isEqualTo(buffer.colorSpace)

        // Color sampling only works on software bitmap.
        val softwareBitmap = resultBitmap.copy(Bitmap.Config.ARGB_8888, false)
        assertThat(softwareBitmap.getPixel(0, 0)).isEqualTo(expectedColor)
    }

    @Test
    fun close_onImageReady_doesNotInvokeCallback() {
        val buffer = FrameBuffer(width = 1, height = 1)
        buffer.beginDrawing().drawColor(Color.RED)
        buffer.endDrawing()

        // Call close before we obtain image.
        buffer.close()

        val latch = CountDownLatch(1)
        var bitmap: Bitmap? = null

        buffer.tryObtainingImage(
            {
                bitmap = it
                latch.countDown()
            },
            executor
        )

        assertThat(latch.await(RESULT_FENCE_TIME_OUT, TimeUnit.MILLISECONDS)).isFalse()
        assertThat(bitmap).isNull()
    }
}