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

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

Merge cherrypicks of ['googleplex-android-review.googlesource.com/34169119',...

Merge cherrypicks of ['googleplex-android-review.googlesource.com/34169119', 'googleplex-android-review.googlesource.com/34393630'] into sparse-13822355-L10500030014351544.
SPARSE_CHANGE: I47e403301602b0f0ce8289d4b8d2a9d30468c066
SPARSE_CHANGE: I36db3f88e9dd7ad8385d35c85d817bbd73beb9dd

Change-Id: I73c13e9e3bbd913c6a6a4e6d82816612b69f35cf
parents 1bab7c05 087a3e16
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -17,17 +17,23 @@
package com.android.customization.picker.icon.data.repository

import com.android.customization.picker.icon.shared.model.IconStyle
import com.android.customization.picker.icon.shared.model.IconStyleModel
import com.android.wallpaper.util.BasePreviewUtils
import kotlinx.coroutines.flow.Flow

interface IconStyleRepository {

    val isThemedIconAvailable: Flow<Boolean>
    val previewUtilsFlow: Flow<BasePreviewUtils?>

    val isCustomizationAvailable: Flow<Boolean>

    val isThemedIconActivated: Flow<Boolean>

    val iconStyles: Flow<List<IconStyle>>
    suspend fun setThemedIconEnabled(enabled: Boolean)

    val iconStyleModels: Flow<List<IconStyleModel>>

    val selectedIconStyle: Flow<IconStyle>

    suspend fun setThemedIconEnabled(enabled: Boolean)
    suspend fun setIconStyle(iconStyle: IconStyle)
}
+52 −14
Original line number Diff line number Diff line
@@ -20,13 +20,18 @@ import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.database.ContentObserver
import android.graphics.drawable.AdaptiveIconDrawable
import android.net.Uri
import com.android.customization.module.CustomizationPreferences
import com.android.customization.picker.icon.shared.model.IconStyle
import com.android.customization.picker.icon.shared.model.IconStyleModel
import com.android.customization.picker.icon.shared.model.ThemePickerIconStyle
import com.android.themepicker.R
import com.android.wallpaper.customization.ui.binder.ShapeIconViewBinder
import com.android.wallpaper.customization.ui.view.ShapeTileDrawable
import com.android.wallpaper.model.Screen
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
import com.android.wallpaper.util.PreviewUtils
import dagger.hilt.android.qualifiers.ApplicationContext
@@ -39,6 +44,7 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
@@ -56,7 +62,7 @@ constructor(
    private val metadataKey = appContext.getString(R.string.themed_icon_metadata_key)
    // TODO (b/424856247): test the retry logic for getting PreviewUtils
    private var previewUtils: PreviewUtils? = null
    private val previewUtilsFlow = flow {
    override val previewUtilsFlow = flow {
        // If PreviewUtils is created too early on start up, the provider (e.g. Launcher) may not be
        // ready, so PreviewUtils#supportsPreview would return false. Only cache previewUtils if it
        // supports previewing. Otherwise, retry when new flow consumers appear.
@@ -69,14 +75,12 @@ constructor(
        }
        emit(previewUtils)
    }
    private var uri: Uri? = null
    private val uriFlow: Flow<Uri?> =
        previewUtilsFlow.map { uri ?: it?.getUri(ICON_THEMED)?.also { result -> uri = result } }
    val themedIconUri: Flow<Uri?> = previewUtilsFlow.map { it?.getUri(ICON_THEMED) }

    override val isThemedIconAvailable: Flow<Boolean> = previewUtilsFlow.map { it != null }
    override val isCustomizationAvailable: Flow<Boolean> = previewUtilsFlow.map { it != null }

    override val isThemedIconActivated: Flow<Boolean> =
        uriFlow
        themedIconUri
            .flatMapLatest {
                callbackFlow {
                    var disposableHandle: DisposableHandle? = null
@@ -108,11 +112,37 @@ constructor(
                initialValue = false,
            )

    override val iconStyles: Flow<List<IconStyle>> =
        isThemedIconAvailable.map { isThemedIconAvailable ->
            var styles = ThemePickerIconStyle.entries.toList()
            if (!isThemedIconAvailable) styles = styles.filter { !it.getIsThemedIcon() }
            styles
    override val iconStyleModels: Flow<List<IconStyleModel>> =
        isCustomizationAvailable.map { isThemedIconAvailable ->
            ThemePickerIconStyle.entries
                .toList()
                // Filter entries if themed icon is not available
                .filter { isThemedIconAvailable || !it.getIsThemedIcon() }
                .map { it.toIconStyleModel() }
        }

    private fun IconStyle.toIconStyleModel(): IconStyleModel {
        return IconStyleModel(
            iconStyle = this,
            nameResId = this.nameResId,
            icon = this.getIcon(),
            isThemedIcon = this == ThemePickerIconStyle.MONOCHROME,
            isExternalLink = false,
        )
    }

    private fun IconStyle.getIcon(): Icon {
        val previewIconPackageName = appContext.resources.getString(R.string.camera_package)
        val appIconDrawable = ShapeIconViewBinder.loadAppIcon(appContext, previewIconPackageName)
        return Icon.Loaded(
            drawable =
                ShapeTileDrawable(
                    context = appContext,
                    icon = appIconDrawable as? AdaptiveIconDrawable,
                    isThemed = this == ThemePickerIconStyle.MONOCHROME,
                ),
            contentDescription = null,
        )
    }

    override val selectedIconStyle =
@@ -147,16 +177,24 @@ constructor(
    }

    override suspend fun setThemedIconEnabled(enabled: Boolean) {
        uri?.let {
        themedIconUri.first()?.let {
            val values = ContentValues()
            values.put(COL_ICON_THEMED_VALUE, enabled)
            contentResolver.update(it, values, /* where= */ null, /* selectionArgs= */ null)
        }
    }

    override suspend fun setIconStyle(iconStyle: IconStyle) {
        themedIconUri.first()?.let {
            val values = ContentValues()
            values.put(COL_ICON_THEMED_VALUE, iconStyle == ThemePickerIconStyle.MONOCHROME)
            contentResolver.update(it, values, /* where= */ null, /* selectionArgs= */ null)
        }
    }

    companion object {
        private const val ICON_THEMED = "icon_themed"
        private const val COL_ICON_THEMED_VALUE = "boolean_value"
        const val ICON_THEMED = "icon_themed"
        const val COL_ICON_THEMED_VALUE = "boolean_value"
        private const val ENABLED = 1
    }
}
+5 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.customization.picker.icon.domain.interactor
import com.android.customization.model.grid.ShapeOptionModel
import com.android.customization.picker.grid.data.repository.ShapeRepository
import com.android.customization.picker.icon.data.repository.IconStyleRepository
import com.android.customization.picker.icon.shared.model.IconStyle
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.flow.Flow
@@ -42,11 +43,11 @@ constructor(

    val isShapeOptionsAvailable: Flow<Boolean> = shapeRepository.isShapeOptionsAvailable

    val isThemedIconAvailable: Flow<Boolean> = iconStyleRepository.isThemedIconAvailable
    val isThemedIconAvailable: Flow<Boolean> = iconStyleRepository.isCustomizationAvailable

    val isThemedIconEnabled: Flow<Boolean> = iconStyleRepository.isThemedIconActivated

    val iconStyles = iconStyleRepository.iconStyles
    val iconStyleModels = iconStyleRepository.iconStyleModels

    val selectedIconStyle = iconStyleRepository.selectedIconStyle

@@ -54,4 +55,6 @@ constructor(
        iconStyleRepository.setThemedIconEnabled(enabled)

    suspend fun applyShape(shapeKey: String) = shapeRepository.applyShape(shapeKey)

    suspend fun applyIconStyle(iconStyle: IconStyle) = iconStyleRepository.setIconStyle(iconStyle)
}
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.customization.picker.icon.shared.model

import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon

open class IconStyleModel(
    val iconStyle: IconStyle,
    val nameResId: Int,
    val icon: Icon?,
    val isThemedIcon: Boolean,
    val isExternalLink: Boolean,
)
+0 −4
Original line number Diff line number Diff line
@@ -25,8 +25,4 @@ enum class ThemePickerIconStyle(override val nameResId: Int) : IconStyle {
    override fun getIsThemedIcon(): Boolean {
        return this == MONOCHROME
    }

    override fun getIsExternalLink(): Boolean {
        return false
    }
}
Loading