1 /*
2  * Copyright (C) 2024 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.power;
18 
19 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
20 
21 import static com.android.server.power.PowerManagerService.WAKE_LOCK_BUTTON_BRIGHT;
22 import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_BRIGHT;
23 import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_DIM;
24 import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_TIMEOUT_OVERRIDE;
25 
26 import android.annotation.IntDef;
27 import android.content.Context;
28 import android.os.PowerManager;
29 import android.util.IndentingPrintWriter;
30 import android.util.Slog;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 
34 import java.io.PrintWriter;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 
38 /**
39   * Policy that handle the screen timeout override wake lock behavior.
40   */
41 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
42 final class ScreenTimeoutOverridePolicy {
43     private static final String TAG = "ScreenTimeoutOverridePolicy";
44 
45     /**
46      * Release reason code: The wake lock is never acquired.
47      */
48     public static final int RELEASE_REASON_UNKNOWN = -1;
49 
50     /**
51      * Release reason code: The wake lock can't be acquired because of screen off.
52      */
53     public static final int RELEASE_REASON_NON_INTERACTIVE = 1;
54 
55     /**
56      * Release reason code: Release because a screen lock is acquired.
57      */
58     public static final int RELEASE_REASON_SCREEN_LOCK = 2;
59 
60     /**
61      * Release reason code: Release because user activity attention occurs.
62      */
63     public static final int RELEASE_REASON_USER_ACTIVITY_ATTENTION = 3;
64 
65     /**
66      * Release reason code: Release because user activity other occurs.
67      */
68     public static final int RELEASE_REASON_USER_ACTIVITY_OTHER = 4;
69 
70     /**
71      * Release reason code: Release because user activity button occurs.
72      */
73     public static final int RELEASE_REASON_USER_ACTIVITY_BUTTON = 5;
74 
75     /**
76      * Release reason code: Release because user activity touch occurs.
77      */
78     public static final int RELEASE_REASON_USER_ACTIVITY_TOUCH = 6;
79 
80     /**
81      * Release reason code: Release because user activity accessibility occurs.
82      */
83     public static final int RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY = 7;
84 
85     /**
86      * @hide
87      */
88     @IntDef(prefix = { "RELEASE_REASON_" }, value = {
89             RELEASE_REASON_UNKNOWN,
90             RELEASE_REASON_NON_INTERACTIVE,
91             RELEASE_REASON_SCREEN_LOCK,
92             RELEASE_REASON_USER_ACTIVITY_ATTENTION,
93             RELEASE_REASON_USER_ACTIVITY_OTHER,
94             RELEASE_REASON_USER_ACTIVITY_BUTTON,
95             RELEASE_REASON_USER_ACTIVITY_TOUCH,
96             RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY
97     })
98     @Retention(RetentionPolicy.SOURCE)
99     public @interface ReleaseReason{}
100 
101     // The screen timeout override config in milliseconds.
102     private long mScreenTimeoutOverrideConfig;
103 
104     // The last reason that wake locks had been released by service.
105     private @ReleaseReason int mLastAutoReleaseReason = RELEASE_REASON_UNKNOWN;
106 
107     interface PolicyCallback {
108         /**
109          * Notify {@link PowerManagerService} to release all override wake locks.
110          */
releaseAllScreenTimeoutOverrideWakelocks(@eleaseReason int reason)111         void releaseAllScreenTimeoutOverrideWakelocks(@ReleaseReason int reason);
112     }
113     private PolicyCallback mPolicyCallback;
114 
ScreenTimeoutOverridePolicy(Context context, long minimumScreenOffTimeoutConfig, PolicyCallback callback)115     ScreenTimeoutOverridePolicy(Context context, long minimumScreenOffTimeoutConfig,
116             PolicyCallback callback) {
117         mScreenTimeoutOverrideConfig = context.getResources().getInteger(
118                 com.android.internal.R.integer.config_screenTimeoutOverride);
119         if (mScreenTimeoutOverrideConfig < minimumScreenOffTimeoutConfig) {
120             Slog.w(TAG, "Screen timeout override is smaller than the minimum timeout : "
121                     + mScreenTimeoutOverrideConfig);
122             mScreenTimeoutOverrideConfig = -1;
123         }
124         mPolicyCallback = callback;
125     }
126 
127     /**
128      * Return the valid screen timeout override value.
129      */
getScreenTimeoutOverrideLocked(int wakeLockSummary, long screenOffTimeout)130     long getScreenTimeoutOverrideLocked(int wakeLockSummary, long screenOffTimeout) {
131         if (!isWakeLockAcquired(wakeLockSummary)) {
132             return screenOffTimeout;
133         }
134 
135         if (mScreenTimeoutOverrideConfig < 0) {
136             return screenOffTimeout;
137         }
138 
139         // If screen timeout overlay wake lock is acquired, return the policy timeout.
140         return Math.min(mScreenTimeoutOverrideConfig, screenOffTimeout);
141     }
142 
143     /**
144      * Called when the policy have to release all wake lock when user activity occurred.
145      */
onUserActivity(int wakeLockSummary, @PowerManager.UserActivityEvent int event)146     void onUserActivity(int wakeLockSummary, @PowerManager.UserActivityEvent int event) {
147         if (!isWakeLockAcquired(wakeLockSummary)) {
148             return;
149         }
150 
151         switch (event) {
152             case PowerManager.USER_ACTIVITY_EVENT_ATTENTION:
153                 releaseAllWakeLocks(RELEASE_REASON_USER_ACTIVITY_ATTENTION);
154                 return;
155             case PowerManager.USER_ACTIVITY_EVENT_OTHER:
156                 releaseAllWakeLocks(RELEASE_REASON_USER_ACTIVITY_OTHER);
157                 return;
158             case PowerManager.USER_ACTIVITY_EVENT_BUTTON:
159                 releaseAllWakeLocks(RELEASE_REASON_USER_ACTIVITY_BUTTON);
160                 return;
161             case PowerManager.USER_ACTIVITY_EVENT_TOUCH:
162                 releaseAllWakeLocks(RELEASE_REASON_USER_ACTIVITY_TOUCH);
163                 return;
164             case PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY:
165                 releaseAllWakeLocks(RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY);
166                 return;
167         }
168     }
169 
170     /**
171      * Check the summary whether a screen wake lock acquired .
172      */
checkScreenWakeLock(int wakeLockSummary)173     void checkScreenWakeLock(int wakeLockSummary) {
174         if (!isWakeLockAcquired(wakeLockSummary)) {
175             return;
176         }
177 
178         if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
179                 | WAKE_LOCK_BUTTON_BRIGHT)) != 0) {
180             releaseAllWakeLocks(RELEASE_REASON_SCREEN_LOCK);
181         }
182     }
183 
184     /**
185      * Check the device is in non-interactive
186      */
onWakefulnessChange(int wakeLockSummary, int globalWakefulness)187     void onWakefulnessChange(int wakeLockSummary, int globalWakefulness) {
188         if (!isWakeLockAcquired(wakeLockSummary)) {
189             return;
190         }
191 
192         if (globalWakefulness != WAKEFULNESS_AWAKE) {
193             releaseAllWakeLocks(RELEASE_REASON_NON_INTERACTIVE);
194         }
195     }
196 
isWakeLockAcquired(int wakeLockSummary)197     private boolean isWakeLockAcquired(int wakeLockSummary) {
198         return (wakeLockSummary & WAKE_LOCK_SCREEN_TIMEOUT_OVERRIDE) != 0;
199     }
200 
logReleaseReason()201     private void logReleaseReason() {
202         Slog.i(TAG, "Releasing all screen timeout override wake lock."
203                 + " (reason=" + mLastAutoReleaseReason + ")");
204     }
205 
releaseAllWakeLocks(@eleaseReason int reason)206     private void releaseAllWakeLocks(@ReleaseReason int reason) {
207         mPolicyCallback.releaseAllScreenTimeoutOverrideWakelocks(reason);
208         mLastAutoReleaseReason = reason;
209         logReleaseReason();
210     }
211 
dump(PrintWriter pw)212     void dump(PrintWriter pw) {
213         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
214 
215         ipw.println();
216         ipw.println("ScreenTimeoutOverridePolicy:");
217         ipw.increaseIndent();
218 
219         ipw.println("mScreenTimeoutOverrideConfig=" + mScreenTimeoutOverrideConfig);
220         ipw.println("mLastAutoReleaseReason=" + mLastAutoReleaseReason);
221     }
222 }
223