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

Commit c5e1cdf6 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge changes from topic "clsqa-in-themepicker" into tm-qpr-dev

* changes:
  Moves client and contract into customization lib.
  Makes camera config dep. lazy.
  Backup & Restore support for quick affordances.
parents 17068514 e5f67447
Loading
Loading
Loading
Loading
+190 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.shared.quickaffordance.data.content

import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine

class FakeKeyguardQuickAffordanceProviderClient(
    slots: List<KeyguardQuickAffordanceProviderClient.Slot> =
        listOf(
            KeyguardQuickAffordanceProviderClient.Slot(
                id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
                capacity = 1,
            ),
            KeyguardQuickAffordanceProviderClient.Slot(
                id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
                capacity = 1,
            ),
        ),
    affordances: List<KeyguardQuickAffordanceProviderClient.Affordance> =
        listOf(
            KeyguardQuickAffordanceProviderClient.Affordance(
                id = AFFORDANCE_1,
                name = AFFORDANCE_1,
                iconResourceId = 0,
            ),
            KeyguardQuickAffordanceProviderClient.Affordance(
                id = AFFORDANCE_2,
                name = AFFORDANCE_2,
                iconResourceId = 0,
            ),
            KeyguardQuickAffordanceProviderClient.Affordance(
                id = AFFORDANCE_3,
                name = AFFORDANCE_3,
                iconResourceId = 0,
            ),
        ),
    flags: List<KeyguardQuickAffordanceProviderClient.Flag> =
        listOf(
            KeyguardQuickAffordanceProviderClient.Flag(
                name = KeyguardQuickAffordanceProviderContract.FlagsTable.FLAG_NAME_FEATURE_ENABLED,
                value = true,
            )
        ),
) : KeyguardQuickAffordanceProviderClient {

    private val slots = MutableStateFlow(slots)
    private val affordances = MutableStateFlow(affordances)
    private val flags = MutableStateFlow(flags)

    private val selections = MutableStateFlow<Map<String, List<String>>>(emptyMap())

    override suspend fun insertSelection(slotId: String, affordanceId: String) {
        val slotCapacity =
            querySlots().find { it.id == slotId }?.capacity
                ?: error("Slot with ID \"$slotId\" not found!")
        val affordances = selections.value.getOrDefault(slotId, mutableListOf()).toMutableList()
        while (affordances.size + 1 > slotCapacity) {
            affordances.removeAt(0)
        }
        affordances.remove(affordanceId)
        affordances.add(affordanceId)
        selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances }
    }

    override suspend fun querySlots(): List<KeyguardQuickAffordanceProviderClient.Slot> {
        return slots.value
    }

    override suspend fun queryFlags(): List<KeyguardQuickAffordanceProviderClient.Flag> {
        return flags.value
    }

    override fun observeSlots(): Flow<List<KeyguardQuickAffordanceProviderClient.Slot>> {
        return slots.asStateFlow()
    }

    override fun observeFlags(): Flow<List<KeyguardQuickAffordanceProviderClient.Flag>> {
        return flags.asStateFlow()
    }

    override suspend fun queryAffordances():
        List<KeyguardQuickAffordanceProviderClient.Affordance> {
        return affordances.value
    }

    override fun observeAffordances():
        Flow<List<KeyguardQuickAffordanceProviderClient.Affordance>> {
        return affordances.asStateFlow()
    }

    override suspend fun querySelections(): List<KeyguardQuickAffordanceProviderClient.Selection> {
        return toSelectionList(selections.value, affordances.value)
    }

    override fun observeSelections(): Flow<List<KeyguardQuickAffordanceProviderClient.Selection>> {
        return combine(selections, affordances) { selections, affordances ->
            toSelectionList(selections, affordances)
        }
    }

    override suspend fun deleteSelection(slotId: String, affordanceId: String) {
        val affordances = selections.value.getOrDefault(slotId, mutableListOf()).toMutableList()
        affordances.remove(affordanceId)

        selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances }
    }

    override suspend fun deleteAllSelections(slotId: String) {
        selections.value = selections.value.toMutableMap().apply { this[slotId] = emptyList() }
    }

    override suspend fun getAffordanceIcon(iconResourceId: Int, tintColor: Int): Drawable {
        return BitmapDrawable()
    }

    fun setFlag(
        name: String,
        value: Boolean,
    ) {
        flags.value =
            flags.value.toMutableList().apply {
                removeIf { it.name == name }
                add(KeyguardQuickAffordanceProviderClient.Flag(name = name, value = value))
            }
    }

    fun setSlotCapacity(slotId: String, capacity: Int) {
        slots.value =
            slots.value.toMutableList().apply {
                val index = indexOfFirst { it.id == slotId }
                check(index != -1) { "Slot with ID \"$slotId\" doesn't exist!" }
                set(
                    index,
                    KeyguardQuickAffordanceProviderClient.Slot(id = slotId, capacity = capacity)
                )
            }
    }

    fun addAffordance(affordance: KeyguardQuickAffordanceProviderClient.Affordance): Int {
        affordances.value = affordances.value + listOf(affordance)
        return affordances.value.size - 1
    }

    private fun toSelectionList(
        selections: Map<String, List<String>>,
        affordances: List<KeyguardQuickAffordanceProviderClient.Affordance>,
    ): List<KeyguardQuickAffordanceProviderClient.Selection> {
        return selections
            .map { (slotId, affordanceIds) ->
                affordanceIds.map { affordanceId ->
                    val affordanceName =
                        affordances.find { it.id == affordanceId }?.name
                            ?: error("No affordance with ID of \"$affordanceId\"!")
                    KeyguardQuickAffordanceProviderClient.Selection(
                        slotId = slotId,
                        affordanceId = affordanceId,
                        affordanceName = affordanceName,
                    )
                }
            }
            .flatten()
    }

    companion object {
        const val AFFORDANCE_1 = "affordance_1"
        const val AFFORDANCE_2 = "affordance_2"
        const val AFFORDANCE_3 = "affordance_3"
    }
}
+479 −0

File added.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
 *
 */

package com.android.systemui.shared.keyguard.data.content
package com.android.systemui.shared.quickaffordance.data.content

import android.content.ContentResolver
import android.net.Uri
+0 −0

File moved.

+33 −17
Original line number Diff line number Diff line
@@ -29,13 +29,15 @@ import android.os.UserHandle
import android.util.Log
import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper
import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
import com.android.systemui.people.widget.PeopleBackupHelper

/**
 * Helper for backing up elements in SystemUI
 *
 * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI.
 * The helper can be used to back up any element that is stored in [Context.getFilesDir].
 * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI. The
 * helper can be used to back up any element that is stored in [Context.getFilesDir] or
 * [Context.getSharedPreferences].
 *
 * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
 * indicating that restoring is finished for a given user.
@@ -47,9 +49,11 @@ open class BackupHelper : BackupAgentHelper() {
        internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
        private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
        private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
        private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY =
            "systemui.keyguard.quickaffordance.shared_preferences"
        val controlsDataLock = Any()
        const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED"
        private const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
        const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
    }

    override fun onCreate(userHandle: UserHandle, operationType: Int) {
@@ -67,13 +71,23 @@ open class BackupHelper : BackupAgentHelper() {
        }

        val keys = PeopleBackupHelper.getFilesToBackup()
        addHelper(PEOPLE_TILES_BACKUP_KEY, PeopleBackupHelper(
                this, userHandle, keys.toTypedArray()))
        addHelper(
            PEOPLE_TILES_BACKUP_KEY,
            PeopleBackupHelper(this, userHandle, keys.toTypedArray())
        )
        addHelper(
            KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY,
            KeyguardQuickAffordanceBackupHelper(
                context = this,
                userId = userHandle.identifier,
            ),
        )
    }

    override fun onRestoreFinished() {
        super.onRestoreFinished()
        val intent = Intent(ACTION_RESTORE_FINISHED).apply {
        val intent =
            Intent(ACTION_RESTORE_FINISHED).apply {
                `package` = packageName
                putExtra(Intent.EXTRA_USER_ID, userId)
                flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -90,7 +104,9 @@ open class BackupHelper : BackupAgentHelper() {
     * @property lock a lock to hold while backing up and restoring the files.
     * @property context the context of the [BackupAgent]
     * @property fileNamesAndPostProcess a map from the filenames to back up and the post processing
     * ```
     *                                   actions to take
     * ```
     */
    private class NoOverwriteFileBackupHelper(
        val lock: Any,
@@ -115,23 +131,23 @@ open class BackupHelper : BackupAgentHelper() {
            data: BackupDataOutput?,
            newState: ParcelFileDescriptor?
        ) {
            synchronized(lock) {
                super.performBackup(oldState, data, newState)
            }
            synchronized(lock) { super.performBackup(oldState, data, newState) }
        }
    }
}

private fun getPPControlsFile(context: Context): () -> Unit {
    return {
        val filesDir = context.filesDir
        val file = Environment.buildPath(filesDir, BackupHelper.CONTROLS)
        if (file.exists()) {
            val dest = Environment.buildPath(filesDir,
                AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
            val dest =
                Environment.buildPath(filesDir, AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
            file.copyTo(dest)
            val jobScheduler = context.getSystemService(JobScheduler::class.java)
            jobScheduler?.schedule(
                AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context))
                AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
            )
        }
    }
}
Loading