1 /*
2  * Copyright (C) 2019 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.server.policy;
18 
19 import android.annotation.IntDef;
20 import android.metrics.LogMaker;
21 import android.os.SystemClock;
22 
23 import com.android.internal.logging.MetricsLogger;
24 import com.android.internal.logging.nano.MetricsProto;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 
29 /**
30  * Logger for tracking duration of usage in folded vs unfolded state.
31  */
32 class DisplayFoldDurationLogger {
33     static final int SCREEN_STATE_UNKNOWN = -1;
34     static final int SCREEN_STATE_OFF = 0;
35     static final int SCREEN_STATE_ON_UNFOLDED = 1;
36     static final int SCREEN_STATE_ON_FOLDED = 2;
37 
38     @IntDef(flag = true, prefix = {"SCREEN_STATE_"}, value = {
39             SCREEN_STATE_UNKNOWN,
40             SCREEN_STATE_OFF,
41             SCREEN_STATE_ON_UNFOLDED,
42             SCREEN_STATE_ON_FOLDED
43     })
44     @Retention(RetentionPolicy.SOURCE)
45     public @interface ScreenState {}
46 
47     private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
48     private Long mLastChanged = null;
49 
50     private static final int LOG_SUBTYPE_UNFOLDED = 0;
51     private static final int LOG_SUBTYPE_FOLDED = 1;
52     private static final int LOG_SUBTYPE_DURATION_MASK = 0x80000000;
53 
54     private final MetricsLogger mLogger = new MetricsLogger();
55 
onFinishedWakingUp(Boolean folded)56     void onFinishedWakingUp(Boolean folded) {
57         if (folded == null) {
58             mScreenState = SCREEN_STATE_UNKNOWN;
59         } else if (folded) {
60             mScreenState = SCREEN_STATE_ON_FOLDED;
61         } else {
62             mScreenState = SCREEN_STATE_ON_UNFOLDED;
63         }
64         mLastChanged = SystemClock.uptimeMillis();
65     }
66 
onFinishedGoingToSleep()67     void onFinishedGoingToSleep() {
68         log();
69         mScreenState = SCREEN_STATE_OFF;
70         mLastChanged = null;
71     }
72 
setDeviceFolded(boolean folded)73     void setDeviceFolded(boolean folded) {
74         // This function is called even when the screen is in ADO mode, but we're only
75         // interested in the case that the screen is actually on.
76         if (!isOn()) {
77             return;
78         }
79         log();
80         mScreenState = folded ? SCREEN_STATE_ON_FOLDED : SCREEN_STATE_ON_UNFOLDED;
81         mLastChanged = SystemClock.uptimeMillis();
82     }
83 
logFocusedAppWithFoldState(boolean folded, String packageName)84     void logFocusedAppWithFoldState(boolean folded, String packageName) {
85         mLogger.write(
86                 new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
87                         .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
88                         .setSubtype(folded ? LOG_SUBTYPE_FOLDED : LOG_SUBTYPE_UNFOLDED)
89                         .setPackageName(packageName));
90     }
91 
log()92     private void log() {
93         if (mLastChanged == null) {
94             return;
95         }
96         int subtype;
97         switch (mScreenState) {
98             case SCREEN_STATE_ON_UNFOLDED:
99                 subtype = LOG_SUBTYPE_UNFOLDED | LOG_SUBTYPE_DURATION_MASK;
100                 break;
101             case SCREEN_STATE_ON_FOLDED:
102                 subtype = LOG_SUBTYPE_FOLDED | LOG_SUBTYPE_DURATION_MASK;
103                 break;
104             default:
105                 return;
106         }
107         mLogger.write(
108                 new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
109                         .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
110                         .setSubtype(subtype)
111                         .setLatency(SystemClock.uptimeMillis() - mLastChanged));
112     }
113 
isOn()114     private boolean isOn() {
115         return mScreenState == SCREEN_STATE_ON_UNFOLDED || mScreenState == SCREEN_STATE_ON_FOLDED;
116     }
117 }
118