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