1 /* 2 * Copyright (C) 2022 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 18 package com.android.systemui.power.data.repository 19 20 import android.content.BroadcastReceiver 21 import android.content.Context 22 import android.content.Intent 23 import android.content.IntentFilter 24 import android.os.PowerManager 25 import com.android.systemui.broadcast.BroadcastDispatcher 26 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 27 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 28 import com.android.systemui.dagger.SysUISingleton 29 import com.android.systemui.dagger.qualifiers.Application 30 import com.android.systemui.util.time.SystemClock 31 import javax.inject.Inject 32 import kotlinx.coroutines.channels.awaitClose 33 import kotlinx.coroutines.flow.Flow 34 35 /** Defines interface for classes that act as source of truth for power-related data. */ 36 interface PowerRepository { 37 /** Whether the device is interactive. Starts with the current state. */ 38 val isInteractive: Flow<Boolean> 39 40 /** Wakes up the device. */ 41 fun wakeUp(why: String, @PowerManager.WakeReason wakeReason: Int) 42 } 43 44 @SysUISingleton 45 class PowerRepositoryImpl 46 @Inject 47 constructor( 48 private val manager: PowerManager, 49 @Application private val applicationContext: Context, 50 private val systemClock: SystemClock, 51 dispatcher: BroadcastDispatcher, 52 ) : PowerRepository { 53 54 override val isInteractive: Flow<Boolean> = conflatedCallbackFlow { 55 fun send() { 56 trySendWithFailureLogging(manager.isInteractive, TAG) 57 } 58 59 val receiver = 60 object : BroadcastReceiver() { 61 override fun onReceive(context: Context?, intent: Intent?) { 62 send() 63 } 64 } 65 66 dispatcher.registerReceiver( 67 receiver, 68 IntentFilter().apply { 69 addAction(Intent.ACTION_SCREEN_ON) 70 addAction(Intent.ACTION_SCREEN_OFF) 71 }, 72 ) 73 send() 74 75 awaitClose { dispatcher.unregisterReceiver(receiver) } 76 } 77 78 override fun wakeUp(why: String, wakeReason: Int) { 79 manager.wakeUp( 80 systemClock.uptimeMillis(), 81 wakeReason, 82 "${applicationContext.packageName}:$why", 83 ) 84 } 85 86 companion object { 87 private const val TAG = "PowerRepository" 88 } 89 } 90