1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.biometrics.domain.interactor 18 19 import android.content.Context 20 import android.content.res.Configuration 21 import com.android.systemui.biometrics.data.repository.DisplayStateRepository 22 import com.android.systemui.biometrics.shared.model.DisplayRotation 23 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 24 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 25 import com.android.systemui.dagger.qualifiers.Application 26 import com.android.systemui.dagger.qualifiers.Main 27 import com.android.systemui.display.data.repository.DisplayRepository 28 import com.android.systemui.unfold.compat.ScreenSizeFoldProvider 29 import com.android.systemui.unfold.updates.FoldProvider 30 import java.util.concurrent.Executor 31 import javax.inject.Inject 32 import kotlinx.coroutines.CoroutineScope 33 import kotlinx.coroutines.channels.awaitClose 34 import kotlinx.coroutines.flow.Flow 35 import kotlinx.coroutines.flow.SharingStarted 36 import kotlinx.coroutines.flow.StateFlow 37 import kotlinx.coroutines.flow.stateIn 38 39 /** Aggregates display state information. */ 40 interface DisplayStateInteractor { 41 /** Whether the default display is currently off. */ 42 val isDefaultDisplayOff: Flow<Boolean> 43 44 /** Whether the device is currently in rear display mode. */ 45 val isInRearDisplayMode: StateFlow<Boolean> 46 47 /** Whether the device is currently folded. */ 48 val isFolded: Flow<Boolean> 49 50 /** Current rotation of the display */ 51 val currentRotation: StateFlow<DisplayRotation> 52 53 /** Display change event indicating a change to the given displayId has occurred. */ 54 val displayChanges: Flow<Int> 55 56 /** 57 * If true, the direction rotation is applied to get to an application's requested orientation 58 * is reversed. Normally, the model is that landscape is clockwise from portrait; thus on a 59 * portrait device an app requesting landscape will cause a clockwise rotation, and on a 60 * landscape device an app requesting portrait will cause a counter-clockwise rotation. Setting 61 * true here reverses that logic. See go/natural-orientation for context. 62 */ 63 val isReverseDefaultRotation: Boolean 64 65 /** Called on configuration changes, used to keep the display state in sync */ 66 fun onConfigurationChanged(newConfig: Configuration) 67 68 /** Provides whether the current display is large screen */ 69 val isLargeScreen: StateFlow<Boolean> 70 } 71 72 /** Encapsulates logic for interacting with the display state. */ 73 class DisplayStateInteractorImpl 74 @Inject 75 constructor( 76 @Application applicationScope: CoroutineScope, 77 @Application context: Context, 78 @Main mainExecutor: Executor, 79 displayStateRepository: DisplayStateRepository, 80 displayRepository: DisplayRepository, 81 ) : DisplayStateInteractor { 82 private var screenSizeFoldProvider: ScreenSizeFoldProvider = ScreenSizeFoldProvider(context) 83 setScreenSizeFoldProvidernull84 fun setScreenSizeFoldProvider(foldProvider: ScreenSizeFoldProvider) { 85 screenSizeFoldProvider = foldProvider 86 } 87 88 override val displayChanges = displayRepository.displayChangeEvent 89 90 override val isFolded: Flow<Boolean> = <lambda>null91 conflatedCallbackFlow { 92 val sendFoldStateUpdate = { state: Boolean -> 93 trySendWithFailureLogging( 94 state, 95 TAG, 96 "Error sending fold state update to $state" 97 ) 98 } 99 100 val callback = 101 object : FoldProvider.FoldCallback { 102 override fun onFoldUpdated(isFolded: Boolean) { 103 sendFoldStateUpdate(isFolded) 104 } 105 } 106 107 sendFoldStateUpdate(false) 108 screenSizeFoldProvider.registerCallback(callback, mainExecutor) 109 awaitClose { screenSizeFoldProvider.unregisterCallback(callback) } 110 } 111 .stateIn( 112 applicationScope, 113 started = SharingStarted.Eagerly, 114 initialValue = false, 115 ) 116 117 override val isInRearDisplayMode: StateFlow<Boolean> = 118 displayStateRepository.isInRearDisplayMode 119 120 override val currentRotation: StateFlow<DisplayRotation> = 121 displayStateRepository.currentRotation 122 123 override val isReverseDefaultRotation: Boolean = displayStateRepository.isReverseDefaultRotation 124 onConfigurationChangednull125 override fun onConfigurationChanged(newConfig: Configuration) { 126 screenSizeFoldProvider.onConfigurationChange(newConfig) 127 } 128 129 override val isDefaultDisplayOff = displayRepository.defaultDisplayOff 130 131 override val isLargeScreen: StateFlow<Boolean> = displayStateRepository.isLargeScreen 132 133 companion object { 134 private const val TAG = "DisplayStateInteractor" 135 } 136 } 137