diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c7ca3b3..fb88a0ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -138,6 +138,8 @@ androidx-media3-common = { module = "androidx.media3:media3-common", version.ref androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" } androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3" } +fresco = "com.facebook.fresco:fresco:3.0.0" +fresco-nativeimagetranscoder = "com.facebook.fresco:nativeimagetranscoder:2.6.0!!" glide = "com.github.bumptech.glide:glide:4.15.1" mdc = "com.google.android.material:material:1.9.0" diff --git a/samples/README.md b/samples/README.md index 2ab70af9..3be50075 100644 --- a/samples/README.md +++ b/samples/README.md @@ -24,8 +24,8 @@ Shows how to create a GATT server and communicate with the GATT client Demonstrates how to implement data access auditing for your app to identify - [Displaying UltraHDR](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDR.kt): This sample demonstrates displaying an UltraHDR image. -- [Displaying UltraHDR (Glide)](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsingGlide.kt): -This sample demonstrates using the Glide image loading library to detect the +- [Displaying UltraHDR (3P Libraries)](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsing3PLibrary.kt): +This sample demonstrates using the various popular image loading libraries to display Ultra HDR images - [Downloadable Fonts](user-interface/text/src/main/java/com/example/platform/ui/text/DownloadableFonts.kt): Download fonts instead of bundling them in the app resources. - [Drag and Drop](user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDrop.kt): diff --git a/samples/graphics/ultrahdr/build.gradle.kts b/samples/graphics/ultrahdr/build.gradle.kts index 2848b663..0c544bab 100644 --- a/samples/graphics/ultrahdr/build.gradle.kts +++ b/samples/graphics/ultrahdr/build.gradle.kts @@ -28,4 +28,8 @@ android { dependencies { // Glide implementation(libs.glide) + + // Fresco + implementation(libs.fresco) + implementation(libs.fresco.nativeimagetranscoder) } \ No newline at end of file diff --git a/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsing3PLibrary.kt b/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsing3PLibrary.kt new file mode 100644 index 00000000..86e40b24 --- /dev/null +++ b/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsing3PLibrary.kt @@ -0,0 +1,260 @@ +/* + * Copyright 2023 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 + * + * https://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.example.platform.graphics.ultrahdr.display + +import android.content.pm.ActivityInfo +import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build.VERSION_CODES +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.RadioButton +import androidx.annotation.RequiresApi +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import coil.ImageLoader +import coil.request.ImageRequest +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.target.CustomViewTarget +import com.bumptech.glide.request.transition.Transition +import com.example.platform.graphics.ultrahdr.databinding.DisplayingUltrahdrUsing3pLibraryBinding +import com.facebook.common.executors.CallerThreadExecutor +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.DataSource +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber +import com.facebook.imagepipeline.image.CloseableImage +import com.facebook.imagepipeline.request.ImageRequestBuilder +import com.google.android.catalog.framework.annotations.Sample +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@Sample( + name = "Displaying UltraHDR (3P Libraries)", + description = "This sample demonstrates using the various popular image loading library to" + + " detect the presence of a gainmap to enable HDR mode when displaying an UltraHDR image", + documentation = "https://github.com/bumptech/glide", + tags = ["UltraHDR"], +) +@RequiresApi(VERSION_CODES.UPSIDE_DOWN_CAKE) +class DisplayingUltraHDRUsing3PLibrary : Fragment() { + private enum class Library(val value: Int) { + GLIDE(0), + FRESCO(1), + COIL(2); + + companion object { + fun fromInt(value: Int) = Library.values().first { it.value == value } + } + } + + /** + * Android ViewBinding. + */ + private var _binding: DisplayingUltrahdrUsing3pLibraryBinding? = null + private val binding get() = _binding!! + + /** + * Current 3p library selected. + */ + private lateinit var currentLibrary: Library + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Initialize Fresco Library + if (!Fresco.hasBeenInitialized()) Fresco.initialize(requireContext()) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = DisplayingUltrahdrUsing3pLibraryBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.colorModeControls.setWindow(requireActivity().window) + + // Disable color mode controls to demonstrate 3P libraries enabling hdr mode when a + // gainmap is is detected. + binding.colorModeControls.binding.ultrahdrColorModeSdr.isEnabled = false + binding.colorModeControls.binding.ultrahdrColorModeSdr.text = "SDR (Automatic)" + binding.colorModeControls.binding.ultrahdrColorModeHdr.isEnabled = false + binding.colorModeControls.binding.ultrahdrColorModeHdr.text = "HDR (Automatic)" + + binding.librarySelectionGroup.setOnCheckedChangeListener { group, i -> + val selected = group.findViewById(i) + val index = group.indexOfChild(selected) + currentLibrary = Library.fromInt(index) + loadWithSelectedLibrary(SDR_IMAGE_URL) + } + + binding.optionSdrImage.setOnClickListener { loadWithSelectedLibrary(SDR_IMAGE_URL) } + binding.optionUltrahdrImage.setOnClickListener { loadWithSelectedLibrary(ULTRAHDR_IMAGE) } + + // Initially load using Glide. + binding.modeGlide.isChecked = true + } + + /** + * Load the image with the currently selected library. + */ + private fun loadWithSelectedLibrary(url: String) { + // Initially null out image bitmap + binding.imageContainer.setImageBitmap(null) + + when (currentLibrary) { + Library.GLIDE -> loadImageWithGlide(url) + Library.FRESCO -> loadImageWithFresco(url) + Library.COIL -> loadImageWithCoil(url) + } + + // Disable corresponding button. + when (url) { + SDR_IMAGE_URL -> { + binding.optionSdrImage.isEnabled = false + binding.optionUltrahdrImage.isEnabled = true + } + + ULTRAHDR_IMAGE -> { + binding.optionSdrImage.isEnabled = true + binding.optionUltrahdrImage.isEnabled = false + } + } + } + + /** + * Load an image using [Glide]. + */ + private fun loadImageWithGlide(path: String) { + Glide.with(this) + .asBitmap() + .load(Uri.parse(path)) + .into(target) + } + + /** + * Using [Glide]s [CustomTarget] class, we can access the given [Bitmap] to check for the + * presence of a gainmap, indicating that we should enable the HDR color mode. + * + * The same could be done with [CustomViewTarget] as well. + */ + private val target: CustomTarget = object : CustomTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + binding.imageContainer.setImageBitmap(resource) + + // Set color mode of the activity to the correct color mode. + requireActivity().window.colorMode = when (resource.hasGainmap()) { + true -> ActivityInfo.COLOR_MODE_HDR + else -> ActivityInfo.COLOR_MODE_DEFAULT + } + } + + override fun onLoadCleared(placeholder: Drawable?) { + // clear resources if need be. + } + } + + /** + * Load an image using [Fresco]. + */ + private fun loadImageWithFresco(path: String) { + val imageRequest = ImageRequestBuilder + .newBuilderWithSource(Uri.parse(path)) + .build() + + // Use Fresco's ImagePipeline to fetch and decode image into Bitmap subscriber. + Fresco.getImagePipeline() + .fetchDecodedImage(imageRequest, this) + .apply { subscribe(subscriber, CallerThreadExecutor.getInstance()) } + } + + /** + * Using [Fresco]'s [BaseBitmapDataSubscriber] class so we can access the given [Bitmap] to + * check for the, presence of a gainmap, indicating that we should enable the HDR color mode. + */ + private val subscriber = object : BaseBitmapDataSubscriber() { + override fun onNewResultImpl(bitmap: Bitmap?) { + binding.imageContainer.setImageBitmap(bitmap) + lifecycleScope.launch { + // Set color mode of the activity to the correct color mode. + requireActivity().window.colorMode = when (bitmap?.hasGainmap()) { + true -> ActivityInfo.COLOR_MODE_HDR + else -> ActivityInfo.COLOR_MODE_DEFAULT + } + } + } + + override fun onFailureImpl(dataSource: DataSource>) { + dataSource.close() + } + } + + /** + * Load an image using [ImageLoader] & [ImageRequest] from Coil. + */ + private fun loadImageWithCoil(url: String) { + lifecycleScope.launch(Dispatchers.IO) { + val loader = ImageLoader(requireContext()) + val request = ImageRequest.Builder(requireContext()) + .data(url) + .crossfade(true) + .crossfade(100) + .build() + + val result = loader.execute(request) + + // convert bitmap from drawable. + val bitmap = (result.drawable as BitmapDrawable).bitmap + + // Activate HDR mode if bitmap has gain map + withContext(Dispatchers.Main) { + binding.imageContainer.setImageBitmap(bitmap) + requireActivity().window.colorMode = when (bitmap.hasGainmap()) { + true -> ActivityInfo.COLOR_MODE_HDR + else -> ActivityInfo.COLOR_MODE_DEFAULT + } + } + } + } + + override fun onDetach() { + super.onDetach() + binding.colorModeControls.detach() + } + + companion object { + /** + * Sample UltraHDR images paths + */ + private const val SDR_IMAGE_URL = + "https://raw.githubusercontent.com/android/platform-samples/main/samples/graphics/" + + "ultrahdr/src/main/assets/sdr/night_highrise.jpg" + private const val ULTRAHDR_IMAGE = + "https://raw.githubusercontent.com/android/platform-samples/main/samples/graphics/" + + "ultrahdr/src/main/assets/gainmaps/night_highrise.jpg" + } +} \ No newline at end of file diff --git a/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsingGlide.kt b/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsingGlide.kt deleted file mode 100644 index 7447dbc7..00000000 --- a/samples/graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/DisplayingUltraHDRUsingGlide.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2023 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 - * - * https://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.example.platform.graphics.ultrahdr.display - -import android.content.pm.ActivityInfo -import android.graphics.Bitmap -import android.graphics.drawable.Drawable -import android.net.Uri -import android.os.Build.VERSION_CODES -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.RequiresApi -import androidx.fragment.app.Fragment -import com.bumptech.glide.Glide -import com.bumptech.glide.request.target.CustomTarget -import com.bumptech.glide.request.target.CustomViewTarget -import com.bumptech.glide.request.transition.Transition -import com.example.platform.graphics.ultrahdr.databinding.DisplayingUltrahdrUsingGlideBinding -import com.google.android.catalog.framework.annotations.Sample - -@Sample( - name = "Displaying UltraHDR (Glide)", - description = "This sample demonstrates using the Glide image loading library to detect the" + - " presence of a gainmap to enable HDR mode when displaying an image using this library.", - documentation = "https://github.com/bumptech/glide", - tags = ["UltraHDR"], -) -@RequiresApi(VERSION_CODES.UPSIDE_DOWN_CAKE) -class DisplayingUltraHDRUsingGlide : Fragment() { - /** - * Android ViewBinding. - */ - private var _binding: DisplayingUltrahdrUsingGlideBinding? = null - private val binding get() = _binding!! - - /** - * Using [Glide]s [CustomTarget] class, we can access the given [Bitmap] to check for the - * presence of a gainmap, indicating that we should enable the HDR color mode. - * - * The same could be done with [CustomViewTarget] as well. - */ - private val target: CustomTarget = object : CustomTarget() { - override fun onResourceReady(resource: Bitmap, transition: Transition?) { - binding.imageContainer.setImageBitmap(resource) - - // Set color mode of the activity to the correct color mode. - requireActivity().window.colorMode = when (resource.hasGainmap()) { - true -> ActivityInfo.COLOR_MODE_HDR - else -> ActivityInfo.COLOR_MODE_DEFAULT - } - } - - override fun onLoadCleared(placeholder: Drawable?) { - // clear resources if need be. - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = DisplayingUltrahdrUsingGlideBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.colorModeControls.setWindow(requireActivity().window) - loadImageWithGlide(SDR_IMAGE) - - // Disable color mode controls to demonstrate glide enabling hdr mode when a gainmap is - // is detected. - binding.colorModeControls.binding.ultrahdrColorModeSdr.isEnabled = false - binding.colorModeControls.binding.ultrahdrColorModeHdr.isEnabled = false - - binding.optionSdrImage.setOnClickListener { loadImageWithGlide(SDR_IMAGE) } - binding.optionUltrahdrImage.setOnClickListener { loadImageWithGlide(ULTRAHDR_IMAGE) } - } - - /** - * Load an image using [Glide]. - */ - private fun loadImageWithGlide(path: String) = - Glide.with(this) - .asBitmap() - .load(Uri.parse(path)) - .into(target) - - override fun onDetach() { - super.onDetach() - binding.colorModeControls.detach() - } - - companion object { - /** - * Sample UltraHDR images paths - */ - private const val SDR_IMAGE = "file:///android_asset/sdr/night_highrise.jpg" - private const val ULTRAHDR_IMAGE = "file:///android_asset/gainmaps/night_highrise.jpg" - } -} \ No newline at end of file diff --git a/samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_glide.xml b/samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_3p_library.xml similarity index 67% rename from samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_glide.xml rename to samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_3p_library.xml index 66a4e6cb..d8084854 100644 --- a/samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_glide.xml +++ b/samples/graphics/ultrahdr/src/main/res/layout/displaying_ultrahdr_using_3p_library.xml @@ -24,6 +24,37 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> + + + + + + + + + - Grand Canyon Train Station + + Glide + Fresco + Coil + SDR JPEG Gainmap @@ -34,7 +39,6 @@ Edit UltraHDR Image Edit Gainmap - SDR HDR