blob: 4611ef9f31dbc85b0b9185a9710dad443540aaa2 [file] [log] [blame]
Jason Monk5dbd4aa2016-02-07 13:13:39 -05001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.statusbar.policy;
16
Jason Monk5dbd4aa2016-02-07 13:13:39 -050017import android.content.BroadcastReceiver;
18import android.content.Context;
19import android.content.Intent;
20import android.content.IntentFilter;
21import android.opengl.Matrix;
Jason Monk5dbd4aa2016-02-07 13:13:39 -050022import android.provider.Settings.Secure;
23import android.util.MathUtils;
Jason Monk5dbd4aa2016-02-07 13:13:39 -050024import com.android.systemui.tuner.TunerService;
25
26import java.util.ArrayList;
27
28/**
29 * Listens for changes to twilight from the TwilightService.
30 *
31 * Also pushes the current matrix to accessibility based on the current twilight
32 * and various tuner settings.
33 */
34public class NightModeController implements TunerService.Tunable {
35
36 public static final String NIGHT_MODE_ADJUST_TINT = "tuner_night_mode_adjust_tint";
37 private static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
38
39 private static final String ACTION_TWILIGHT_CHANGED = "android.intent.action.TWILIGHT_CHANGED";
40
41 private static final String EXTRA_IS_NIGHT = "isNight";
42 private static final String EXTRA_AMOUNT = "amount";
43
44 // Night mode ~= 3400 K
45 private static final float[] NIGHT_VALUES = new float[] {
46 1, 0, 0, 0,
47 0, .754f, 0, 0,
48 0, 0, .516f, 0,
49 0, 0, 0, 1,
50 };
51 public static final float[] IDENTITY_MATRIX = new float[] {
52 1, 0, 0, 0,
53 0, 1, 0, 0,
54 0, 0, 1, 0,
55 0, 0, 0, 1,
56 };
57
58 private final ArrayList<Listener> mListeners = new ArrayList<>();
59
60 private final Context mContext;
61
62 // This is whether or not this is the main NightMode controller in SysUI that should be
63 // updating relevant color matrixes or if its in the tuner process getting current state
64 // for UI.
65 private final boolean mUpdateMatrix;
66
67 private float[] mCustomMatrix;
68 private boolean mListening;
69 private boolean mAdjustTint;
70
71 private boolean mIsNight;
72 private float mAmount;
73 private boolean mIsAuto;
74
75 public NightModeController(Context context) {
76 this(context, false);
77 }
78
79 public NightModeController(Context context, boolean updateMatrix) {
80 mContext = context;
81 mUpdateMatrix = updateMatrix;
82 TunerService.get(mContext).addTunable(this, NIGHT_MODE_ADJUST_TINT,
83 COLOR_MATRIX_CUSTOM_VALUES, Secure.TWILIGHT_MODE);
84 }
85
86 public void setNightMode(boolean isNight) {
87 if (mIsAuto) {
88 if (mIsNight != isNight) {
89 TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
90 ? Secure.TWILIGHT_MODE_AUTO_OVERRIDE_ON
91 : Secure.TWILIGHT_MODE_AUTO_OVERRIDE_OFF);
92 } else {
93 TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE,
94 Secure.TWILIGHT_MODE_AUTO);
95 }
96 } else {
97 TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
98 ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
99 }
100 }
101
102 public void setAuto(boolean auto) {
103 mIsAuto = auto;
104 if (auto) {
105 TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_AUTO);
106 } else {
107 // Lock into the current state
108 TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, mIsNight
109 ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
110 }
111 }
112
113 public boolean isAuto() {
114 return mIsAuto;
115 }
116
117 public void setAdjustTint(Boolean newValue) {
118 TunerService.get(mContext).setValue(NIGHT_MODE_ADJUST_TINT, ((Boolean) newValue) ? 1 : 0);
119 }
120
121 public void addListener(Listener listener) {
122 mListeners.add(listener);
123 listener.onNightModeChanged();
124 updateListening();
125 }
126
127 public void removeListener(Listener listener) {
128 mListeners.remove(listener);
129 updateListening();
130 }
131
132 private void updateListening() {
133 boolean shouldListen = mListeners.size() != 0 || (mUpdateMatrix && mAdjustTint);
134 if (shouldListen == mListening) return;
135 mListening = shouldListen;
136 if (mListening) {
137 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_TWILIGHT_CHANGED));
138 } else {
139 mContext.unregisterReceiver(mReceiver);
140 }
141 }
142
143 public boolean isEnabled() {
144 if (!mListening) {
145 updateNightMode(mContext.registerReceiver(null,
146 new IntentFilter(ACTION_TWILIGHT_CHANGED)));
147 }
148 return mIsNight;
149 }
150
151 public String getCustomValues() {
152 return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
153 }
154
155 public void setCustomValues(String values) {
156 TunerService.get(mContext).setValue(COLOR_MATRIX_CUSTOM_VALUES, values);
157 }
158
159 @Override
160 public void onTuningChanged(String key, String newValue) {
161 if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
162 mCustomMatrix = newValue != null ? toValues(newValue) : null;
163 updateCurrentMatrix();
164 } else if (NIGHT_MODE_ADJUST_TINT.equals(key)) {
165 mAdjustTint = newValue == null || Integer.parseInt(newValue) != 0;
166 updateListening();
167 updateCurrentMatrix();
168 } else if (Secure.TWILIGHT_MODE.equals(key)) {
169 mIsAuto = newValue != null && Integer.parseInt(newValue) >= Secure.TWILIGHT_MODE_AUTO;
170 }
171 }
172
173 private void updateCurrentMatrix() {
174 if (!mUpdateMatrix) return;
175 if ((!mAdjustTint || mAmount == 0) && mCustomMatrix == null) {
176 TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
177 return;
178 }
179 float[] values = scaleValues(IDENTITY_MATRIX, NIGHT_VALUES, mAdjustTint ? mAmount : 0);
180 if (mCustomMatrix != null) {
181 values = multiply(values, mCustomMatrix);
182 }
183 TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
184 toString(values));
185 }
186
187 private void updateNightMode(Intent intent) {
Jason Monk46dbfb42016-02-25 14:59:20 -0500188 mIsNight = intent != null && intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
189 mAmount = intent != null ? intent.getFloatExtra(EXTRA_AMOUNT, 0) : 0;
Jason Monk5dbd4aa2016-02-07 13:13:39 -0500190 }
191
192 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
193 @Override
194 public void onReceive(Context context, Intent intent) {
195 if (ACTION_TWILIGHT_CHANGED.equals(intent.getAction())) {
196 updateNightMode(intent);
197 updateCurrentMatrix();
198 for (int i = 0; i < mListeners.size(); i++) {
199 mListeners.get(i).onNightModeChanged();
200 }
201 }
202 }
203 };
204
205 public interface Listener {
206 void onNightModeChanged();
207 void onTwilightAutoChanged();
208 }
209
210 private static float[] multiply(float[] matrix, float[] other) {
211 if (matrix == null) {
212 return other;
213 }
214 float[] result = new float[16];
215 Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
216 return result;
217 }
218
219 private float[] scaleValues(float[] identityMatrix, float[] nightValues, float amount) {
220 float[] values = new float[identityMatrix.length];
221 for (int i = 0; i < values.length; i++) {
222 values[i] = MathUtils.lerp(identityMatrix[i], nightValues[i], amount);
223 }
224 return values;
225 }
226
227 public static String toString(float[] values) {
228 StringBuilder builder = new StringBuilder();
229 for (int i = 0; i < values.length; i++) {
230 if (builder.length() != 0) {
231 builder.append(',');
232 }
233 builder.append(values[i]);
234 }
235 return builder.toString();
236 }
237
238 public static float[] toValues(String customValues) {
239 String[] strValues = customValues.split(",");
240 float[] values = new float[strValues.length];
241 for (int i = 0; i < values.length; i++) {
242 values[i] = Float.parseFloat(strValues[i]);
243 }
244 return values;
245 }
246}