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.keyguard.ui.binder 18 19 import android.animation.ValueAnimator 20 import android.graphics.Point 21 import com.android.systemui.CoreStartable 22 import com.android.systemui.Flags 23 import com.android.systemui.dagger.SysUISingleton 24 import com.android.systemui.dagger.qualifiers.Application 25 import com.android.systemui.keyguard.ui.view.SideFpsProgressBar 26 import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel 27 import com.android.systemui.log.SideFpsLogger 28 import com.android.systemui.statusbar.commandline.Command 29 import com.android.systemui.statusbar.commandline.CommandRegistry 30 import com.android.systemui.util.kotlin.Quint 31 import java.io.PrintWriter 32 import javax.inject.Inject 33 import kotlinx.coroutines.CoroutineScope 34 import kotlinx.coroutines.Job 35 import kotlinx.coroutines.flow.collectLatest 36 import kotlinx.coroutines.flow.combine 37 import kotlinx.coroutines.launch 38 39 private const val sfpsProgressBarCommand = "sfps-progress-bar" 40 41 @SysUISingleton 42 class SideFpsProgressBarViewBinder 43 @Inject 44 constructor( 45 private val viewModel: SideFpsProgressBarViewModel, 46 private val view: SideFpsProgressBar, 47 @Application private val applicationScope: CoroutineScope, 48 private val logger: SideFpsLogger, 49 private val commandRegistry: CommandRegistry, 50 ) : CoreStartable { 51 52 override fun start() { 53 if (!Flags.restToUnlock()) { 54 return 55 } 56 // When the rest to unlock feature is disabled by the user, stop any coroutines that are 57 // not required. 58 var layoutJob: Job? = null 59 var progressJob: Job? = null 60 commandRegistry.registerCommand(sfpsProgressBarCommand) { SfpsProgressBarCommand() } 61 applicationScope.launch { 62 viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> 63 logger.isProlongedTouchRequiredForAuthenticationChanged(enabled) 64 if (enabled) { 65 layoutJob = launch { 66 combine( 67 viewModel.isVisible, 68 viewModel.progressBarLocation, 69 viewModel.rotation, 70 viewModel.isFingerprintAuthRunning, 71 viewModel.progressBarLength, 72 ::Quint 73 ) 74 .collectLatest { (visible, location, rotation, fpDetectRunning, length) 75 -> 76 updateView( 77 visible, 78 location, 79 fpDetectRunning, 80 length, 81 viewModel.progressBarThickness, 82 rotation, 83 ) 84 } 85 } 86 progressJob = launch { 87 viewModel.progress.collectLatest { view.setProgress(it) } 88 } 89 } else { 90 view.hide() 91 layoutJob?.cancel() 92 progressJob?.cancel() 93 } 94 } 95 } 96 } 97 98 private fun updateView( 99 visible: Boolean, 100 location: Point, 101 fpDetectRunning: Boolean, 102 length: Int, 103 thickness: Int, 104 rotation: Float, 105 ) { 106 logger.sfpsProgressBarStateChanged(visible, location, fpDetectRunning, length, rotation) 107 view.updateView(visible, location, length, thickness, rotation) 108 } 109 110 inner class SfpsProgressBarCommand : Command { 111 private var animator: ValueAnimator? = null 112 override fun execute(pw: PrintWriter, args: List<String>) { 113 if (args.isEmpty() || args[0] == "show" && args.size != 6) { 114 pw.println("invalid command") 115 help(pw) 116 } else { 117 when (args[0]) { 118 "show" -> { 119 animator?.cancel() 120 updateView( 121 visible = true, 122 location = Point(Integer.parseInt(args[1]), Integer.parseInt(args[2])), 123 fpDetectRunning = true, 124 length = Integer.parseInt(args[3]), 125 thickness = Integer.parseInt(args[4]), 126 rotation = Integer.parseInt(args[5]).toFloat(), 127 ) 128 animator = 129 ValueAnimator.ofFloat(0.0f, 1.0f).apply { 130 repeatMode = ValueAnimator.REVERSE 131 repeatCount = ValueAnimator.INFINITE 132 addUpdateListener { view.setProgress(it.animatedValue as Float) } 133 } 134 animator?.start() 135 } 136 "hide" -> { 137 animator?.cancel() 138 updateView( 139 visible = false, 140 location = Point(0, 0), 141 fpDetectRunning = false, 142 length = 0, 143 thickness = 0, 144 rotation = 0.0f, 145 ) 146 } 147 } 148 } 149 } 150 151 override fun help(pw: PrintWriter) { 152 pw.println("Usage: adb shell cmd statusbar $sfpsProgressBarCommand <command>") 153 pw.println("Available commands:") 154 pw.println(" show x y width height rotation") 155 pw.println(" hide") 156 } 157 } 158 } 159