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

Commit cd605ec2 authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge "Move NotificationsInteractor & related repos to shared." into main

parents 7c04808c 7678de9e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -277,6 +277,7 @@ android_library {
        "SystemUIPluginLib",
        "SystemUISharedLib",
        "SystemUICustomizationLib",
        "SystemUICustomizationTestUtils",
        "SystemUI-statsd",
        "SettingsLib",
        "com_android_systemui_flags_lib",
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
 *
 *      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.notifications.data.repository

import android.provider.Settings
import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.withContext

/** Provides access to state related to notifications. */
class NotificationSettingsRepository(
    scope: CoroutineScope,
    private val backgroundDispatcher: CoroutineDispatcher,
    private val secureSettingsRepository: SecureSettingsRepository,
) {
    /** The current state of the notification setting. */
    val settings: SharedFlow<NotificationSettingsModel> =
        secureSettingsRepository
            .intSetting(
                name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
            )
            .map { lockScreenShowNotificationsInt ->
                NotificationSettingsModel(
                    isShowNotificationsOnLockScreenEnabled = lockScreenShowNotificationsInt == 1,
                )
            }
            .shareIn(
                scope = scope,
                started = SharingStarted.WhileSubscribed(),
                replay = 1,
            )

    suspend fun getSettings(): NotificationSettingsModel {
        return withContext(backgroundDispatcher) {
            NotificationSettingsModel(
                isShowNotificationsOnLockScreenEnabled =
                    secureSettingsRepository.get(
                        name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                        defaultValue = 0,
                    ) == 1
            )
        }
    }

    suspend fun setSettings(model: NotificationSettingsModel) {
        withContext(backgroundDispatcher) {
            secureSettingsRepository.set(
                name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                value = if (model.isShowNotificationsOnLockScreenEnabled) 1 else 0,
            )
        }
    }
}
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
 *
 *      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.notifications.domain.interactor

import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
import kotlinx.coroutines.flow.Flow

/** Encapsulates business logic for interacting with notification settings. */
class NotificationSettingsInteractor(
    private val repository: NotificationSettingsRepository,
) {
    /** The current state of the notification setting. */
    val settings: Flow<NotificationSettingsModel> = repository.settings

    /** Toggles the setting to show or hide notifications on the lock screen. */
    suspend fun toggleShowNotificationsOnLockScreenEnabled() {
        val currentModel = repository.getSettings()
        setSettings(
            currentModel.copy(
                isShowNotificationsOnLockScreenEnabled =
                    !currentModel.isShowNotificationsOnLockScreenEnabled,
            )
        )
    }

    suspend fun setSettings(model: NotificationSettingsModel) {
        repository.setSettings(model)
    }

    suspend fun getSettings(): NotificationSettingsModel {
        return repository.getSettings()
    }
}
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
 *
 *      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.notifications.shared.model

/** Models notification settings. */
data class NotificationSettingsModel(
    /** Whether notifications are shown on the lock screen. */
    val isShowNotificationsOnLockScreenEnabled: Boolean = false,
)
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
 *
 *      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.settings.data.repository

import android.content.ContentResolver
import android.database.ContentObserver
import android.provider.Settings
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext

/** Defines interface for classes that can provide access to data from [Settings.Secure]. */
interface SecureSettingsRepository {

    /** Returns a [Flow] tracking the value of a setting as an [Int]. */
    fun intSetting(
        name: String,
        defaultValue: Int = 0,
    ): Flow<Int>

    /** Updates the value of the setting with the given name. */
    suspend fun set(
        name: String,
        value: Int,
    )

    suspend fun get(
        name: String,
        defaultValue: Int = 0,
    ): Int
}

class SecureSettingsRepositoryImpl(
    private val contentResolver: ContentResolver,
    private val backgroundDispatcher: CoroutineDispatcher,
) : SecureSettingsRepository {

    override fun intSetting(
        name: String,
        defaultValue: Int,
    ): Flow<Int> {
        return callbackFlow {
                val observer =
                    object : ContentObserver(null) {
                        override fun onChange(selfChange: Boolean) {
                            trySend(Unit)
                        }
                    }

                contentResolver.registerContentObserver(
                    Settings.Secure.getUriFor(name),
                    /* notifyForDescendants= */ false,
                    observer,
                )
                send(Unit)

                awaitClose { contentResolver.unregisterContentObserver(observer) }
            }
            .map { Settings.Secure.getInt(contentResolver, name, defaultValue) }
            // The above work is done on the background thread (which is important for accessing
            // settings through the content resolver).
            .flowOn(backgroundDispatcher)
    }

    override suspend fun set(name: String, value: Int) {
        withContext(backgroundDispatcher) {
            Settings.Secure.putInt(
                contentResolver,
                name,
                value,
            )
        }
    }

    override suspend fun get(name: String, defaultValue: Int): Int {
        return withContext(backgroundDispatcher) {
            Settings.Secure.getInt(
                contentResolver,
                name,
                defaultValue,
            )
        }
    }
}
Loading