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 android.hardware.display;
18 
19 import android.annotation.NonNull;
20 import android.annotation.UserIdInt;
21 import android.app.ActivityManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.database.ContentObserver;
25 import android.net.Uri;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.provider.Settings.Secure;
29 
30 import java.time.LocalTime;
31 
32 /**
33  * @hide
34  */
35 public class NightDisplayListener {
36 
37     private final Context mContext;
38     private final ColorDisplayManager mManager;
39     private final Handler mHandler;
40     private final ContentObserver mContentObserver;
41     private final int mUserId;
42 
43     private Callback mCallback;
44 
NightDisplayListener(@onNull Context context)45     public NightDisplayListener(@NonNull Context context) {
46         this(context, ActivityManager.getCurrentUser(), new Handler(Looper.getMainLooper()));
47     }
48 
NightDisplayListener(@onNull Context context, @NonNull Handler handler)49     public NightDisplayListener(@NonNull Context context, @NonNull Handler handler) {
50         this(context, ActivityManager.getCurrentUser(), handler);
51     }
52 
NightDisplayListener(@onNull Context context, @UserIdInt int userId, @NonNull Handler handler)53     public NightDisplayListener(@NonNull Context context, @UserIdInt int userId,
54             @NonNull Handler handler) {
55         mContext = context.getApplicationContext();
56         mManager = mContext.getSystemService(ColorDisplayManager.class);
57         mUserId = userId;
58 
59         mHandler = handler;
60         mContentObserver = new ContentObserver(mHandler) {
61             @Override
62             public void onChange(boolean selfChange, Uri uri) {
63                 super.onChange(selfChange, uri);
64                 final String setting = uri == null ? null : uri.getLastPathSegment();
65                 if (setting != null && mCallback != null) {
66                     switch (setting) {
67                         case Secure.NIGHT_DISPLAY_ACTIVATED:
68                             mCallback.onActivated(mManager.isNightDisplayActivated());
69                             break;
70                         case Secure.NIGHT_DISPLAY_AUTO_MODE:
71                             mCallback.onAutoModeChanged(mManager.getNightDisplayAutoMode());
72                             break;
73                         case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
74                             mCallback.onCustomStartTimeChanged(
75                                     mManager.getNightDisplayCustomStartTime());
76                             break;
77                         case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
78                             mCallback.onCustomEndTimeChanged(
79                                     mManager.getNightDisplayCustomEndTime());
80                             break;
81                         case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
82                             mCallback.onColorTemperatureChanged(
83                                     mManager.getNightDisplayColorTemperature());
84                             break;
85                     }
86                 }
87             }
88         };
89     }
90 
91     /**
92      * Register a callback to be invoked whenever the Night display settings are changed.
93      */
setCallback(Callback callback)94     public void setCallback(Callback callback) {
95         if (Looper.myLooper() != mHandler.getLooper()) {
96             mHandler.post(() -> setCallbackInternal(callback));
97         }
98         setCallbackInternal(callback);
99     }
100 
setCallbackInternal(Callback newCallback)101     private void setCallbackInternal(Callback newCallback) {
102         final Callback oldCallback = mCallback;
103         if (oldCallback != newCallback) {
104             mCallback = newCallback;
105             if (mCallback == null) {
106                 mContext.getContentResolver().unregisterContentObserver(mContentObserver);
107             } else if (oldCallback == null) {
108                 final ContentResolver cr = mContext.getContentResolver();
109                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
110                         false /* notifyForDescendants */, mContentObserver, mUserId);
111                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
112                         false /* notifyForDescendants */, mContentObserver, mUserId);
113                 cr.registerContentObserver(
114                         Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
115                         false /* notifyForDescendants */, mContentObserver, mUserId);
116                 cr.registerContentObserver(
117                         Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
118                         false /* notifyForDescendants */, mContentObserver, mUserId);
119                 cr.registerContentObserver(
120                         Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
121                         false /* notifyForDescendants */, mContentObserver, mUserId);
122             }
123         }
124     }
125 
126     /**
127      * Callback invoked whenever the Night display settings are changed.
128      */
129     public interface Callback {
130 
131         /**
132          * Callback invoked when the activated state changes.
133          *
134          * @param activated {@code true} if Night display is activated
135          */
onActivated(boolean activated)136         default void onActivated(boolean activated) {
137         }
138 
139         /**
140          * Callback invoked when the auto mode changes.
141          *
142          * @param autoMode the auto mode to use
143          */
onAutoModeChanged(int autoMode)144         default void onAutoModeChanged(int autoMode) {
145         }
146 
147         /**
148          * Callback invoked when the time to automatically activate Night display changes.
149          *
150          * @param startTime the local time to automatically activate Night display
151          */
onCustomStartTimeChanged(LocalTime startTime)152         default void onCustomStartTimeChanged(LocalTime startTime) {
153         }
154 
155         /**
156          * Callback invoked when the time to automatically deactivate Night display changes.
157          *
158          * @param endTime the local time to automatically deactivate Night display
159          */
onCustomEndTimeChanged(LocalTime endTime)160         default void onCustomEndTimeChanged(LocalTime endTime) {
161         }
162 
163         /**
164          * Callback invoked when the color temperature changes.
165          *
166          * @param colorTemperature the color temperature to tint the screen
167          */
onColorTemperatureChanged(int colorTemperature)168         default void onColorTemperatureChanged(int colorTemperature) {
169         }
170     }
171 }
172