• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.systemui.unfold
18 
19 import android.util.Log
20 import com.android.systemui.unfold.FoldStateLoggingProvider.FoldStateLoggingListener
21 import com.android.systemui.unfold.FoldStateLoggingProvider.LoggedFoldedStates
22 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
23 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
24 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
25 import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
26 import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
27 import com.android.systemui.unfold.updates.FoldStateProvider
28 import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
29 import com.android.systemui.util.time.SystemClock
30 
31 /**
32  * Reports device fold states for logging purposes.
33  *
34  * Wraps the state provided by [FoldStateProvider] to output only [FULLY_OPENED], [FULLY_CLOSED] and
35  * [HALF_OPENED] for logging purposes.
36  *
37  * Note that [HALF_OPENED] state is only emitted after the device angle is stable for some timeout.
38  * Check [FoldStateProvider] impl for it.
39  *
40  * This doesn't log the following transitions:
41  * - [HALF_OPENED] -> [FULLY_OPENED]: not interesting, as there is no transition going on
42  * - [HALF_OPENED] -> [HALF_OPENED]: not meaningful.
43  */
44 class FoldStateLoggingProviderImpl(
45     private val foldStateProvider: FoldStateProvider,
46     private val clock: SystemClock
47 ) : FoldStateLoggingProvider, FoldStateProvider.FoldUpdatesListener {
48 
49     private val outputListeners: MutableList<FoldStateLoggingListener> = mutableListOf()
50 
51     @LoggedFoldedStates private var lastState: Int? = null
52     private var actionStartMillis: Long? = null
53 
initnull54     override fun init() {
55         foldStateProvider.addCallback(this)
56         foldStateProvider.start()
57     }
58 
uninitnull59     override fun uninit() {
60         foldStateProvider.removeCallback(this)
61         foldStateProvider.stop()
62     }
63 
onFoldUpdatenull64     override fun onFoldUpdate(@FoldUpdate update: Int) {
65         val now = clock.elapsedRealtime()
66         when (update) {
67             FOLD_UPDATE_START_OPENING -> {
68                 lastState = FULLY_CLOSED
69                 actionStartMillis = now
70             }
71             FOLD_UPDATE_START_CLOSING -> actionStartMillis = now
72             FOLD_UPDATE_FINISH_HALF_OPEN -> dispatchState(HALF_OPENED)
73             FOLD_UPDATE_FINISH_FULL_OPEN -> dispatchState(FULLY_OPENED)
74             FOLD_UPDATE_FINISH_CLOSED -> dispatchState(FULLY_CLOSED)
75         }
76     }
77 
onUnfoldedScreenAvailablenull78     override fun onUnfoldedScreenAvailable() {
79         Log.d(TAG, "Unfolded screen available")
80     }
81 
dispatchStatenull82     private fun dispatchState(@LoggedFoldedStates current: Int) {
83         val now = clock.elapsedRealtime()
84         val previous = lastState
85         val lastActionStart = actionStartMillis
86 
87         if (previous != null && previous != current && lastActionStart != null) {
88             val time = now - lastActionStart
89             val foldStateChange = FoldStateChange(previous, current, time)
90             outputListeners.forEach { it.onFoldUpdate(foldStateChange) }
91             if (DEBUG) {
92                 Log.d(TAG, "From $previous to $current in $time")
93             }
94         }
95 
96         actionStartMillis = null
97         lastState = current
98     }
99 
addCallbacknull100     override fun addCallback(listener: FoldStateLoggingListener) {
101         outputListeners.add(listener)
102     }
103 
removeCallbacknull104     override fun removeCallback(listener: FoldStateLoggingListener) {
105         outputListeners.remove(listener)
106     }
107 }
108 
109 private const val DEBUG = false
110 private const val TAG = "FoldStateLoggingProviderImpl"
111