1 /*
2  * 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 package com.android.launcher3.util;
17 
18 import static android.content.Intent.ACTION_SCREEN_OFF;
19 import static android.content.Intent.ACTION_SCREEN_ON;
20 import static android.content.Intent.ACTION_USER_PRESENT;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 
25 import java.util.concurrent.CopyOnWriteArrayList;
26 
27 /**
28  * Utility class for tracking if the screen is currently on or off
29  */
30 public class ScreenOnTracker implements SafeCloseable {
31 
32     public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
33             new MainThreadInitializedObject<>(ScreenOnTracker::new);
34 
35     private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
36     private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
37 
38     private final Context mContext;
39     private boolean mIsScreenOn;
40 
ScreenOnTracker(Context context)41     private ScreenOnTracker(Context context) {
42         // Assume that the screen is on to begin with
43         mContext = context;
44         mIsScreenOn = true;
45         mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
46     }
47 
48     @Override
close()49     public void close() {
50         mReceiver.unregisterReceiverSafely(mContext);
51     }
52 
onReceive(Intent intent)53     private void onReceive(Intent intent) {
54         String action = intent.getAction();
55         if (ACTION_SCREEN_ON.equals(action)) {
56             mIsScreenOn = true;
57             dispatchScreenOnChanged();
58         } else if (ACTION_SCREEN_OFF.equals(action)) {
59             mIsScreenOn = false;
60             dispatchScreenOnChanged();
61         } else if (ACTION_USER_PRESENT.equals(action)) {
62             mListeners.forEach(ScreenOnListener::onUserPresent);
63         }
64     }
65 
dispatchScreenOnChanged()66     private void dispatchScreenOnChanged() {
67         mListeners.forEach(l -> l.onScreenOnChanged(mIsScreenOn));
68     }
69 
70     /** Returns if the screen is on or not */
isScreenOn()71     public boolean isScreenOn() {
72         return mIsScreenOn;
73     }
74 
75     /** Adds a listener for screen on changes */
addListener(ScreenOnListener listener)76     public void addListener(ScreenOnListener listener) {
77         mListeners.add(listener);
78     }
79 
80     /** Removes a previously added listener */
removeListener(ScreenOnListener listener)81     public void removeListener(ScreenOnListener listener) {
82         mListeners.remove(listener);
83     }
84 
85     /**
86      * Interface to listen for screen on changes
87      */
88     public interface ScreenOnListener {
89 
90         /**
91          * Called when the screen turns on/off
92          */
onScreenOnChanged(boolean isOn)93         void onScreenOnChanged(boolean isOn);
94 
95         /**
96          * Called when the keyguard goes away
97          */
onUserPresent()98         default void onUserPresent() { }
99     }
100 }
101