blob: 407fad0c9fe883308c5c4b9b8345ba5a8bbcdb79 [file] [log] [blame]
Kenny Guy22bd0442017-10-26 00:15:54 +01001/*
2 * Copyright 2017 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
17package com.android.server.display;
18
19import android.annotation.Nullable;
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000020import android.annotation.UserIdInt;
Kenny Guy22bd0442017-10-26 00:15:54 +010021import android.app.ActivityManager;
22import android.content.BroadcastReceiver;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.ParceledListSlice;
Kenny Guy3d7172c2018-03-19 14:18:23 +000028import android.database.ContentObserver;
Kenny Guy22bd0442017-10-26 00:15:54 +010029import android.hardware.Sensor;
30import android.hardware.SensorEvent;
31import android.hardware.SensorEventListener;
32import android.hardware.SensorManager;
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000033import android.hardware.display.AmbientBrightnessDayStats;
Kenny Guy22bd0442017-10-26 00:15:54 +010034import android.hardware.display.BrightnessChangeEvent;
Kenny Guy3d7172c2018-03-19 14:18:23 +000035import android.net.Uri;
Kenny Guy22bd0442017-10-26 00:15:54 +010036import android.os.BatteryManager;
37import android.os.Environment;
38import android.os.Handler;
Michael Wright144aac92017-12-21 18:37:41 +000039import android.os.Looper;
40import android.os.Message;
Kenny Guy689ab8f2017-11-29 12:12:06 +000041import android.os.PowerManager;
Kenny Guy22bd0442017-10-26 00:15:54 +010042import android.os.RemoteException;
43import android.os.SystemClock;
44import android.os.UserHandle;
45import android.os.UserManager;
46import android.provider.Settings;
47import android.util.AtomicFile;
48import android.util.Slog;
49import android.util.Xml;
50
51import com.android.internal.annotations.GuardedBy;
52import com.android.internal.annotations.VisibleForTesting;
53import com.android.internal.os.BackgroundThread;
54import com.android.internal.util.FastXmlSerializer;
55import com.android.internal.util.RingBuffer;
56
57import libcore.io.IoUtils;
58
59import org.xmlpull.v1.XmlPullParser;
60import org.xmlpull.v1.XmlPullParserException;
61import org.xmlpull.v1.XmlSerializer;
62
63import java.io.File;
64import java.io.FileInputStream;
65import java.io.FileOutputStream;
66import java.io.IOException;
67import java.io.InputStream;
68import java.io.OutputStream;
Kenny Guycfe7b702017-11-14 21:04:58 +000069import java.io.PrintWriter;
Kenny Guy22bd0442017-10-26 00:15:54 +010070import java.nio.charset.StandardCharsets;
71import java.util.ArrayDeque;
72import java.util.ArrayList;
73
Peeyush Agarwaldb860eb2018-03-07 16:21:50 +000074import java.util.Collections;
Kenny Guy22bd0442017-10-26 00:15:54 +010075import java.util.Deque;
Kenny Guy6c90d8a2018-02-20 16:53:27 +000076import java.util.HashMap;
77import java.util.Map;
Kenny Guy22bd0442017-10-26 00:15:54 +010078import java.util.concurrent.TimeUnit;
79
80/**
81 * Class that tracks recent brightness settings changes and stores
82 * associated information such as light sensor readings.
83 */
84public class BrightnessTracker {
85
Kenny Guycfe7b702017-11-14 21:04:58 +000086 static final String TAG = "BrightnessTracker";
87 static final boolean DEBUG = false;
Kenny Guy22bd0442017-10-26 00:15:54 +010088
89 private static final String EVENTS_FILE = "brightness_events.xml";
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000090 private static final String AMBIENT_BRIGHTNESS_STATS_FILE = "ambient_brightness_stats.xml";
Kenny Guy22bd0442017-10-26 00:15:54 +010091 private static final int MAX_EVENTS = 100;
92 // Discard events when reading or writing that are older than this.
93 private static final long MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(30);
94 // Time over which we keep lux sensor readings.
95 private static final long LUX_EVENT_HORIZON = TimeUnit.SECONDS.toNanos(10);
96
97 private static final String TAG_EVENTS = "events";
98 private static final String TAG_EVENT = "event";
Michael Wright144aac92017-12-21 18:37:41 +000099 private static final String ATTR_NITS = "nits";
Kenny Guy22bd0442017-10-26 00:15:54 +0100100 private static final String ATTR_TIMESTAMP = "timestamp";
101 private static final String ATTR_PACKAGE_NAME = "packageName";
102 private static final String ATTR_USER = "user";
103 private static final String ATTR_LUX = "lux";
104 private static final String ATTR_LUX_TIMESTAMPS = "luxTimestamps";
105 private static final String ATTR_BATTERY_LEVEL = "batteryLevel";
106 private static final String ATTR_NIGHT_MODE = "nightMode";
107 private static final String ATTR_COLOR_TEMPERATURE = "colorTemperature";
Michael Wright144aac92017-12-21 18:37:41 +0000108 private static final String ATTR_LAST_NITS = "lastNits";
Kenny Guy53d06612018-01-30 14:19:13 +0000109 private static final String ATTR_DEFAULT_CONFIG = "defaultConfig";
110 private static final String ATTR_POWER_SAVE = "powerSaveFactor";
111 private static final String ATTR_USER_POINT = "userPoint";
Michael Wright144aac92017-12-21 18:37:41 +0000112
113 private static final int MSG_BACKGROUND_START = 0;
114 private static final int MSG_BRIGHTNESS_CHANGED = 1;
Kenny Guy3d7172c2018-03-19 14:18:23 +0000115 private static final int MSG_STOP_SENSOR_LISTENER = 2;
116 private static final int MSG_START_SENSOR_LISTENER = 3;
Kenny Guy22bd0442017-10-26 00:15:54 +0100117
118 // Lock held while accessing mEvents, is held while writing events to flash.
119 private final Object mEventsLock = new Object();
120 @GuardedBy("mEventsLock")
121 private RingBuffer<BrightnessChangeEvent> mEvents
122 = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
Kenny Guycfe7b702017-11-14 21:04:58 +0000123 @GuardedBy("mEventsLock")
124 private boolean mEventsDirty;
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000125
126 private volatile boolean mWriteBrightnessTrackerStateScheduled;
Kenny Guy22bd0442017-10-26 00:15:54 +0100127
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000128 private AmbientBrightnessStatsTracker mAmbientBrightnessStatsTracker;
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000129
Kenny Guy22bd0442017-10-26 00:15:54 +0100130 private UserManager mUserManager;
131 private final Context mContext;
132 private final ContentResolver mContentResolver;
133 private Handler mBgHandler;
Kenny Guy3d7172c2018-03-19 14:18:23 +0000134
135 // mBroadcastReceiver, mSensorListener, mSettingsObserver and mSensorRegistered
136 // should only be used on the mBgHandler thread.
Kenny Guy22bd0442017-10-26 00:15:54 +0100137 private BroadcastReceiver mBroadcastReceiver;
138 private SensorListener mSensorListener;
Kenny Guy3d7172c2018-03-19 14:18:23 +0000139 private SettingsObserver mSettingsObserver;
140 private boolean mSensorRegistered;
141
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000142 private @UserIdInt int mCurrentUserId = UserHandle.USER_NULL;
Kenny Guy22bd0442017-10-26 00:15:54 +0100143
144 // Lock held while collecting data related to brightness changes.
145 private final Object mDataCollectionLock = new Object();
146 @GuardedBy("mDataCollectionLock")
147 private Deque<LightData> mLastSensorReadings = new ArrayDeque<>();
148 @GuardedBy("mDataCollectionLock")
149 private float mLastBatteryLevel = Float.NaN;
150 @GuardedBy("mDataCollectionLock")
Michael Wright144aac92017-12-21 18:37:41 +0000151 private float mLastBrightness = -1;
Kenny Guy22bd0442017-10-26 00:15:54 +0100152 @GuardedBy("mDataCollectionLock")
Michael Wright144aac92017-12-21 18:37:41 +0000153 private boolean mStarted;
Kenny Guy22bd0442017-10-26 00:15:54 +0100154
155 private final Injector mInjector;
156
157 public BrightnessTracker(Context context, @Nullable Injector injector) {
158 // Note this will be called very early in boot, other system
159 // services may not be present.
160 mContext = context;
161 mContentResolver = context.getContentResolver();
162 if (injector != null) {
163 mInjector = injector;
164 } else {
165 mInjector = new Injector();
166 }
167 }
168
Michael Wright144aac92017-12-21 18:37:41 +0000169 /**
170 * Start listening for brightness slider events
171 *
Kenny Guy0ff44892018-01-10 14:06:42 +0000172 * @param initialBrightness the initial screen brightness
Michael Wright144aac92017-12-21 18:37:41 +0000173 */
174 public void start(float initialBrightness) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100175 if (DEBUG) {
176 Slog.d(TAG, "Start");
177 }
Michael Wright144aac92017-12-21 18:37:41 +0000178 mBgHandler = new TrackerHandler(mInjector.getBackgroundHandler().getLooper());
Kenny Guy22bd0442017-10-26 00:15:54 +0100179 mUserManager = mContext.getSystemService(UserManager.class);
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000180 mCurrentUserId = ActivityManager.getCurrentUser();
Michael Wright144aac92017-12-21 18:37:41 +0000181 mBgHandler.obtainMessage(MSG_BACKGROUND_START, (Float) initialBrightness).sendToTarget();
Kenny Guy22bd0442017-10-26 00:15:54 +0100182 }
183
Michael Wright144aac92017-12-21 18:37:41 +0000184 private void backgroundStart(float initialBrightness) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100185 readEvents();
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000186 readAmbientBrightnessStats();
Kenny Guy22bd0442017-10-26 00:15:54 +0100187
Kenny Guy22bd0442017-10-26 00:15:54 +0100188 mSensorListener = new SensorListener();
Kenny Guy689ab8f2017-11-29 12:12:06 +0000189
Kenny Guy3d7172c2018-03-19 14:18:23 +0000190 mSettingsObserver = new SettingsObserver(mBgHandler);
191 mInjector.registerBrightnessModeObserver(mContentResolver, mSettingsObserver);
192 startSensorListener();
Kenny Guy22bd0442017-10-26 00:15:54 +0100193
Kenny Guy22bd0442017-10-26 00:15:54 +0100194 final IntentFilter intentFilter = new IntentFilter();
195 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
196 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
Kenny Guy689ab8f2017-11-29 12:12:06 +0000197 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
198 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Kenny Guy22bd0442017-10-26 00:15:54 +0100199 mBroadcastReceiver = new Receiver();
200 mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter);
Kenny Guycfe7b702017-11-14 21:04:58 +0000201
202 mInjector.scheduleIdleJob(mContext);
Michael Wright144aac92017-12-21 18:37:41 +0000203 synchronized (mDataCollectionLock) {
204 mLastBrightness = initialBrightness;
205 mStarted = true;
206 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100207 }
208
209 /** Stop listening for events */
210 @VisibleForTesting
211 void stop() {
212 if (DEBUG) {
213 Slog.d(TAG, "Stop");
214 }
Michael Wright144aac92017-12-21 18:37:41 +0000215 mBgHandler.removeMessages(MSG_BACKGROUND_START);
Kenny Guy3d7172c2018-03-19 14:18:23 +0000216 stopSensorListener();
Kenny Guy22bd0442017-10-26 00:15:54 +0100217 mInjector.unregisterSensorListener(mContext, mSensorListener);
Kenny Guy3d7172c2018-03-19 14:18:23 +0000218 mInjector.unregisterBrightnessModeObserver(mContext, mSettingsObserver);
Kenny Guy22bd0442017-10-26 00:15:54 +0100219 mInjector.unregisterReceiver(mContext, mBroadcastReceiver);
Kenny Guycfe7b702017-11-14 21:04:58 +0000220 mInjector.cancelIdleJob(mContext);
Michael Wright144aac92017-12-21 18:37:41 +0000221
222 synchronized (mDataCollectionLock) {
223 mStarted = false;
224 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100225 }
226
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000227 public void onSwitchUser(@UserIdInt int newUserId) {
228 if (DEBUG) {
229 Slog.d(TAG, "Used id updated from " + mCurrentUserId + " to " + newUserId);
230 }
231 mCurrentUserId = newUserId;
232 }
233
Kenny Guy22bd0442017-10-26 00:15:54 +0100234 /**
235 * @param userId userId to fetch data for.
Kenny Guy29aa30e2017-11-30 13:43:46 +0000236 * @param includePackage if false we will null out BrightnessChangeEvent.packageName
Kenny Guy22bd0442017-10-26 00:15:54 +0100237 * @return List of recent {@link BrightnessChangeEvent}s
238 */
Kenny Guy29aa30e2017-11-30 13:43:46 +0000239 public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId, boolean includePackage) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100240 BrightnessChangeEvent[] events;
241 synchronized (mEventsLock) {
242 events = mEvents.toArray();
243 }
Kenny Guy6c90d8a2018-02-20 16:53:27 +0000244 int[] profiles = mInjector.getProfileIds(mUserManager, userId);
245 Map<Integer, Boolean> toRedact = new HashMap<>();
246 for (int i = 0; i < profiles.length; ++i) {
247 int profileId = profiles[i];
248 // Include slider interactions when a managed profile app is in the
249 // foreground but always redact the package name.
250 boolean redact = (!includePackage) || profileId != userId;
251 toRedact.put(profiles[i], redact);
252 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100253 ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length);
254 for (int i = 0; i < events.length; ++i) {
Kenny Guy6c90d8a2018-02-20 16:53:27 +0000255 Boolean redact = toRedact.get(events[i].userId);
256 if (redact != null) {
257 if (!redact) {
Kenny Guy29aa30e2017-11-30 13:43:46 +0000258 out.add(events[i]);
259 } else {
Kenny Guy0ff44892018-01-10 14:06:42 +0000260 BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]),
261 /* redactPackage */ true);
Kenny Guy29aa30e2017-11-30 13:43:46 +0000262 out.add(event);
263 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100264 }
265 }
266 return new ParceledListSlice<>(out);
267 }
268
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000269 public void persistBrightnessTrackerState() {
270 scheduleWriteBrightnessTrackerState();
Kenny Guycfe7b702017-11-14 21:04:58 +0000271 }
272
Michael Wright144aac92017-12-21 18:37:41 +0000273 /**
274 * Notify the BrightnessTracker that the user has changed the brightness of the display.
275 */
Kenny Guy53d06612018-01-30 14:19:13 +0000276 public void notifyBrightnessChanged(float brightness, boolean userInitiated,
277 float powerBrightnessFactor, boolean isUserSetBrightness,
278 boolean isDefaultBrightnessConfig) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100279 if (DEBUG) {
Michael Wright144aac92017-12-21 18:37:41 +0000280 Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)",
281 brightness, userInitiated));
Kenny Guy22bd0442017-10-26 00:15:54 +0100282 }
Michael Wright144aac92017-12-21 18:37:41 +0000283 Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED,
Kenny Guy53d06612018-01-30 14:19:13 +0000284 userInitiated ? 1 : 0, 0 /*unused*/, new BrightnessChangeValues(brightness,
Kenny Guy2b326bf2018-04-18 18:42:10 +0100285 powerBrightnessFactor, isUserSetBrightness, isDefaultBrightnessConfig,
286 mInjector.currentTimeMillis()));
Michael Wright144aac92017-12-21 18:37:41 +0000287 m.sendToTarget();
288 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100289
Kenny Guy53d06612018-01-30 14:19:13 +0000290 private void handleBrightnessChanged(float brightness, boolean userInitiated,
291 float powerBrightnessFactor, boolean isUserSetBrightness,
Kenny Guy2b326bf2018-04-18 18:42:10 +0100292 boolean isDefaultBrightnessConfig, long timestamp) {
Kenny Guy0ff44892018-01-10 14:06:42 +0000293 BrightnessChangeEvent.Builder builder;
294
Kenny Guy22bd0442017-10-26 00:15:54 +0100295 synchronized (mDataCollectionLock) {
Michael Wright144aac92017-12-21 18:37:41 +0000296 if (!mStarted) {
297 // Not currently gathering brightness change information
Kenny Guy22bd0442017-10-26 00:15:54 +0100298 return;
299 }
300
Michael Wright144aac92017-12-21 18:37:41 +0000301 float previousBrightness = mLastBrightness;
302 mLastBrightness = brightness;
303
304 if (!userInitiated) {
305 // We want to record what current brightness is so that we know what the user
306 // changed it from, but if it wasn't user initiated then we don't want to record it
307 // as a BrightnessChangeEvent.
308 return;
309 }
310
Kenny Guy0ff44892018-01-10 14:06:42 +0000311 builder = new BrightnessChangeEvent.Builder();
312 builder.setBrightness(brightness);
Kenny Guy2b326bf2018-04-18 18:42:10 +0100313 builder.setTimeStamp(timestamp);
Kenny Guy53d06612018-01-30 14:19:13 +0000314 builder.setPowerBrightnessFactor(powerBrightnessFactor);
315 builder.setUserBrightnessPoint(isUserSetBrightness);
316 builder.setIsDefaultBrightnessConfig(isDefaultBrightnessConfig);
Michael Wright144aac92017-12-21 18:37:41 +0000317
Kenny Guy22bd0442017-10-26 00:15:54 +0100318 final int readingCount = mLastSensorReadings.size();
319 if (readingCount == 0) {
320 // No sensor data so ignore this.
321 return;
322 }
323
Kenny Guy0ff44892018-01-10 14:06:42 +0000324 float[] luxValues = new float[readingCount];
325 long[] luxTimestamps = new long[readingCount];
Kenny Guy22bd0442017-10-26 00:15:54 +0100326
327 int pos = 0;
328
329 // Convert sensor timestamp in elapsed time nanos to current time millis.
330 long currentTimeMillis = mInjector.currentTimeMillis();
331 long elapsedTimeNanos = mInjector.elapsedRealtimeNanos();
332 for (LightData reading : mLastSensorReadings) {
Kenny Guy0ff44892018-01-10 14:06:42 +0000333 luxValues[pos] = reading.lux;
334 luxTimestamps[pos] = currentTimeMillis -
Kenny Guy22bd0442017-10-26 00:15:54 +0100335 TimeUnit.NANOSECONDS.toMillis(elapsedTimeNanos - reading.timestamp);
336 ++pos;
337 }
Kenny Guy0ff44892018-01-10 14:06:42 +0000338 builder.setLuxValues(luxValues);
339 builder.setLuxTimestamps(luxTimestamps);
Kenny Guy22bd0442017-10-26 00:15:54 +0100340
Kenny Guy0ff44892018-01-10 14:06:42 +0000341 builder.setBatteryLevel(mLastBatteryLevel);
342 builder.setLastBrightness(previousBrightness);
Kenny Guy22bd0442017-10-26 00:15:54 +0100343 }
344
Kenny Guy22bd0442017-10-26 00:15:54 +0100345 try {
346 final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
Kenny Guy0e875d32018-02-26 14:11:40 +0000347 if (focusedStack != null && focusedStack.topActivity != null) {
348 builder.setUserId(focusedStack.userId);
349 builder.setPackageName(focusedStack.topActivity.getPackageName());
350 } else {
351 // Ignore the event because we can't determine user / package.
352 if (DEBUG) {
353 Slog.d(TAG, "Ignoring event due to null focusedStack.");
354 }
355 return;
356 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100357 } catch (RemoteException e) {
358 // Really shouldn't be possible.
Kenny Guy0ff44892018-01-10 14:06:42 +0000359 return;
Kenny Guy22bd0442017-10-26 00:15:54 +0100360 }
361
Kenny Guy0ff44892018-01-10 14:06:42 +0000362 builder.setNightMode(mInjector.getSecureIntForUser(mContentResolver,
Kenny Guy22bd0442017-10-26 00:15:54 +0100363 Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 0, UserHandle.USER_CURRENT)
Kenny Guy0ff44892018-01-10 14:06:42 +0000364 == 1);
365 builder.setColorTemperature(mInjector.getSecureIntForUser(mContentResolver,
Kenny Guy22bd0442017-10-26 00:15:54 +0100366 Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
Kenny Guy0ff44892018-01-10 14:06:42 +0000367 0, UserHandle.USER_CURRENT));
Kenny Guy22bd0442017-10-26 00:15:54 +0100368
Kenny Guy0ff44892018-01-10 14:06:42 +0000369 BrightnessChangeEvent event = builder.build();
Kenny Guy22bd0442017-10-26 00:15:54 +0100370 if (DEBUG) {
371 Slog.d(TAG, "Event " + event.brightness + " " + event.packageName);
372 }
373 synchronized (mEventsLock) {
Kenny Guycfe7b702017-11-14 21:04:58 +0000374 mEventsDirty = true;
Kenny Guy22bd0442017-10-26 00:15:54 +0100375 mEvents.append(event);
376 }
377 }
378
Kenny Guy3d7172c2018-03-19 14:18:23 +0000379 private void startSensorListener() {
380 if (!mSensorRegistered
381 && mInjector.isInteractive(mContext)
382 && mInjector.isBrightnessModeAutomatic(mContentResolver)) {
383 mAmbientBrightnessStatsTracker.start();
384 mSensorRegistered = true;
385 mInjector.registerSensorListener(mContext, mSensorListener,
386 mInjector.getBackgroundHandler());
387 }
388 }
389
390 private void stopSensorListener() {
391 if (mSensorRegistered) {
392 mAmbientBrightnessStatsTracker.stop();
393 mInjector.unregisterSensorListener(mContext, mSensorListener);
394 mSensorRegistered = false;
395 }
396 }
397
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000398 private void scheduleWriteBrightnessTrackerState() {
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000399 if (!mWriteBrightnessTrackerStateScheduled) {
400 mBgHandler.post(() -> {
401 mWriteBrightnessTrackerStateScheduled = false;
402 writeEvents();
403 writeAmbientBrightnessStats();
404 });
405 mWriteBrightnessTrackerStateScheduled = true;
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000406 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100407 }
408
409 private void writeEvents() {
Kenny Guy22bd0442017-10-26 00:15:54 +0100410 synchronized (mEventsLock) {
Kenny Guycfe7b702017-11-14 21:04:58 +0000411 if (!mEventsDirty) {
412 // Nothing to write
413 return;
414 }
415
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000416 final AtomicFile writeTo = mInjector.getFile(EVENTS_FILE);
Kenny Guy22bd0442017-10-26 00:15:54 +0100417 if (writeTo == null) {
418 return;
419 }
420 if (mEvents.isEmpty()) {
421 if (writeTo.exists()) {
422 writeTo.delete();
423 }
Kenny Guycfe7b702017-11-14 21:04:58 +0000424 mEventsDirty = false;
Kenny Guy22bd0442017-10-26 00:15:54 +0100425 } else {
426 FileOutputStream output = null;
427 try {
428 output = writeTo.startWrite();
429 writeEventsLocked(output);
430 writeTo.finishWrite(output);
Kenny Guycfe7b702017-11-14 21:04:58 +0000431 mEventsDirty = false;
Kenny Guy22bd0442017-10-26 00:15:54 +0100432 } catch (IOException e) {
433 writeTo.failWrite(output);
434 Slog.e(TAG, "Failed to write change mEvents.", e);
435 }
436 }
437 }
438 }
439
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000440 private void writeAmbientBrightnessStats() {
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000441 final AtomicFile writeTo = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE);
442 if (writeTo == null) {
443 return;
444 }
445 FileOutputStream output = null;
446 try {
447 output = writeTo.startWrite();
448 mAmbientBrightnessStatsTracker.writeStats(output);
449 writeTo.finishWrite(output);
450 } catch (IOException e) {
451 writeTo.failWrite(output);
452 Slog.e(TAG, "Failed to write ambient brightness stats.", e);
453 }
454 }
455
Kenny Guy22bd0442017-10-26 00:15:54 +0100456 private void readEvents() {
457 synchronized (mEventsLock) {
Kenny Guycfe7b702017-11-14 21:04:58 +0000458 // Read might prune events so mark as dirty.
459 mEventsDirty = true;
Kenny Guy22bd0442017-10-26 00:15:54 +0100460 mEvents.clear();
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000461 final AtomicFile readFrom = mInjector.getFile(EVENTS_FILE);
Kenny Guy22bd0442017-10-26 00:15:54 +0100462 if (readFrom != null && readFrom.exists()) {
463 FileInputStream input = null;
464 try {
465 input = readFrom.openRead();
466 readEventsLocked(input);
467 } catch (IOException e) {
468 readFrom.delete();
469 Slog.e(TAG, "Failed to read change mEvents.", e);
470 } finally {
471 IoUtils.closeQuietly(input);
472 }
473 }
474 }
475 }
476
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000477 private void readAmbientBrightnessStats() {
478 mAmbientBrightnessStatsTracker = new AmbientBrightnessStatsTracker(mUserManager, null);
479 final AtomicFile readFrom = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE);
480 if (readFrom != null && readFrom.exists()) {
481 FileInputStream input = null;
482 try {
483 input = readFrom.openRead();
484 mAmbientBrightnessStatsTracker.readStats(input);
485 } catch (IOException e) {
486 readFrom.delete();
487 Slog.e(TAG, "Failed to read ambient brightness stats.", e);
488 } finally {
489 IoUtils.closeQuietly(input);
490 }
491 }
492 }
493
Kenny Guy22bd0442017-10-26 00:15:54 +0100494 @VisibleForTesting
495 @GuardedBy("mEventsLock")
496 void writeEventsLocked(OutputStream stream) throws IOException {
497 XmlSerializer out = new FastXmlSerializer();
498 out.setOutput(stream, StandardCharsets.UTF_8.name());
499 out.startDocument(null, true);
500 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
501
502 out.startTag(null, TAG_EVENTS);
503 BrightnessChangeEvent[] toWrite = mEvents.toArray();
Kenny Guycfe7b702017-11-14 21:04:58 +0000504 // Clear events, code below will add back the ones that are still within the time window.
505 mEvents.clear();
Kenny Guy22bd0442017-10-26 00:15:54 +0100506 if (DEBUG) {
507 Slog.d(TAG, "Writing events " + toWrite.length);
508 }
Kenny Guycfe7b702017-11-14 21:04:58 +0000509 final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE;
Kenny Guy22bd0442017-10-26 00:15:54 +0100510 for (int i = 0; i < toWrite.length; ++i) {
511 int userSerialNo = mInjector.getUserSerialNumber(mUserManager, toWrite[i].userId);
512 if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) {
Kenny Guycfe7b702017-11-14 21:04:58 +0000513 mEvents.append(toWrite[i]);
Kenny Guy22bd0442017-10-26 00:15:54 +0100514 out.startTag(null, TAG_EVENT);
Michael Wright144aac92017-12-21 18:37:41 +0000515 out.attribute(null, ATTR_NITS, Float.toString(toWrite[i].brightness));
Kenny Guy22bd0442017-10-26 00:15:54 +0100516 out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp));
517 out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
518 out.attribute(null, ATTR_USER, Integer.toString(userSerialNo));
519 out.attribute(null, ATTR_BATTERY_LEVEL, Float.toString(toWrite[i].batteryLevel));
520 out.attribute(null, ATTR_NIGHT_MODE, Boolean.toString(toWrite[i].nightMode));
521 out.attribute(null, ATTR_COLOR_TEMPERATURE, Integer.toString(
522 toWrite[i].colorTemperature));
Michael Wright144aac92017-12-21 18:37:41 +0000523 out.attribute(null, ATTR_LAST_NITS,
524 Float.toString(toWrite[i].lastBrightness));
Kenny Guy53d06612018-01-30 14:19:13 +0000525 out.attribute(null, ATTR_DEFAULT_CONFIG,
526 Boolean.toString(toWrite[i].isDefaultBrightnessConfig));
527 out.attribute(null, ATTR_POWER_SAVE,
528 Float.toString(toWrite[i].powerBrightnessFactor));
529 out.attribute(null, ATTR_USER_POINT,
530 Boolean.toString(toWrite[i].isUserSetBrightness));
Kenny Guy22bd0442017-10-26 00:15:54 +0100531 StringBuilder luxValues = new StringBuilder();
532 StringBuilder luxTimestamps = new StringBuilder();
533 for (int j = 0; j < toWrite[i].luxValues.length; ++j) {
534 if (j > 0) {
535 luxValues.append(',');
536 luxTimestamps.append(',');
537 }
538 luxValues.append(Float.toString(toWrite[i].luxValues[j]));
539 luxTimestamps.append(Long.toString(toWrite[i].luxTimestamps[j]));
540 }
541 out.attribute(null, ATTR_LUX, luxValues.toString());
542 out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString());
543 out.endTag(null, TAG_EVENT);
544 }
545 }
546 out.endTag(null, TAG_EVENTS);
547 out.endDocument();
548 stream.flush();
549 }
550
551 @VisibleForTesting
552 @GuardedBy("mEventsLock")
553 void readEventsLocked(InputStream stream) throws IOException {
554 try {
555 XmlPullParser parser = Xml.newPullParser();
556 parser.setInput(stream, StandardCharsets.UTF_8.name());
557
558 int type;
559 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
560 && type != XmlPullParser.START_TAG) {
561 }
562 String tag = parser.getName();
563 if (!TAG_EVENTS.equals(tag)) {
564 throw new XmlPullParserException(
565 "Events not found in brightness tracker file " + tag);
566 }
567
568 final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE;
569
570 parser.next();
571 int outerDepth = parser.getDepth();
572 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
573 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
574 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
575 continue;
576 }
577 tag = parser.getName();
578 if (TAG_EVENT.equals(tag)) {
Kenny Guy0ff44892018-01-10 14:06:42 +0000579 BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
Kenny Guy22bd0442017-10-26 00:15:54 +0100580
Michael Wright144aac92017-12-21 18:37:41 +0000581 String brightness = parser.getAttributeValue(null, ATTR_NITS);
Kenny Guy0ff44892018-01-10 14:06:42 +0000582 builder.setBrightness(Float.parseFloat(brightness));
Kenny Guy22bd0442017-10-26 00:15:54 +0100583 String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
Kenny Guy0ff44892018-01-10 14:06:42 +0000584 builder.setTimeStamp(Long.parseLong(timestamp));
585 builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
Kenny Guy22bd0442017-10-26 00:15:54 +0100586 String user = parser.getAttributeValue(null, ATTR_USER);
Kenny Guy0ff44892018-01-10 14:06:42 +0000587 builder.setUserId(mInjector.getUserId(mUserManager, Integer.parseInt(user)));
Kenny Guy22bd0442017-10-26 00:15:54 +0100588 String batteryLevel = parser.getAttributeValue(null, ATTR_BATTERY_LEVEL);
Kenny Guy0ff44892018-01-10 14:06:42 +0000589 builder.setBatteryLevel(Float.parseFloat(batteryLevel));
Kenny Guy22bd0442017-10-26 00:15:54 +0100590 String nightMode = parser.getAttributeValue(null, ATTR_NIGHT_MODE);
Kenny Guy0ff44892018-01-10 14:06:42 +0000591 builder.setNightMode(Boolean.parseBoolean(nightMode));
Kenny Guy22bd0442017-10-26 00:15:54 +0100592 String colorTemperature =
593 parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
Kenny Guy0ff44892018-01-10 14:06:42 +0000594 builder.setColorTemperature(Integer.parseInt(colorTemperature));
Michael Wright144aac92017-12-21 18:37:41 +0000595 String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_NITS);
Kenny Guy0ff44892018-01-10 14:06:42 +0000596 builder.setLastBrightness(Float.parseFloat(lastBrightness));
Kenny Guy22bd0442017-10-26 00:15:54 +0100597
598 String luxValue = parser.getAttributeValue(null, ATTR_LUX);
599 String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
600
Kenny Guy0ff44892018-01-10 14:06:42 +0000601 String[] luxValuesStrings = luxValue.split(",");
602 String[] luxTimestampsStrings = luxTimestamp.split(",");
603 if (luxValuesStrings.length != luxTimestampsStrings.length) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100604 continue;
605 }
Kenny Guy0ff44892018-01-10 14:06:42 +0000606 float[] luxValues = new float[luxValuesStrings.length];
607 long[] luxTimestamps = new long[luxValuesStrings.length];
Kenny Guy22bd0442017-10-26 00:15:54 +0100608 for (int i = 0; i < luxValues.length; ++i) {
Kenny Guy0ff44892018-01-10 14:06:42 +0000609 luxValues[i] = Float.parseFloat(luxValuesStrings[i]);
610 luxTimestamps[i] = Long.parseLong(luxTimestampsStrings[i]);
Kenny Guy22bd0442017-10-26 00:15:54 +0100611 }
Kenny Guy0ff44892018-01-10 14:06:42 +0000612 builder.setLuxValues(luxValues);
613 builder.setLuxTimestamps(luxTimestamps);
Kenny Guy22bd0442017-10-26 00:15:54 +0100614
Kenny Guy53d06612018-01-30 14:19:13 +0000615 String defaultConfig = parser.getAttributeValue(null, ATTR_DEFAULT_CONFIG);
616 if (defaultConfig != null) {
617 builder.setIsDefaultBrightnessConfig(Boolean.parseBoolean(defaultConfig));
618 }
619 String powerSave = parser.getAttributeValue(null, ATTR_POWER_SAVE);
620 if (powerSave != null) {
621 builder.setPowerBrightnessFactor(Float.parseFloat(powerSave));
622 } else {
623 builder.setPowerBrightnessFactor(1.0f);
624 }
625 String userPoint = parser.getAttributeValue(null, ATTR_USER_POINT);
626 if (userPoint != null) {
627 builder.setUserBrightnessPoint(Boolean.parseBoolean(userPoint));
628 }
629
Kenny Guy0ff44892018-01-10 14:06:42 +0000630 BrightnessChangeEvent event = builder.build();
Kenny Guy22bd0442017-10-26 00:15:54 +0100631 if (DEBUG) {
632 Slog.i(TAG, "Read event " + event.brightness
633 + " " + event.packageName);
634 }
635
636 if (event.userId != -1 && event.timeStamp > timeCutOff
637 && event.luxValues.length > 0) {
638 mEvents.append(event);
639 }
640 }
641 }
642 } catch (NullPointerException | NumberFormatException | XmlPullParserException
643 | IOException e) {
644 // Failed to parse something, just start with an empty event log.
645 mEvents = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
646 Slog.e(TAG, "Failed to parse brightness event", e);
647 // Re-throw so we will delete the bad file.
648 throw new IOException("failed to parse file", e);
649 }
650 }
651
Kenny Guycfe7b702017-11-14 21:04:58 +0000652 public void dump(PrintWriter pw) {
Kenny Guye1674e52017-11-30 16:25:26 +0000653 pw.println("BrightnessTracker state:");
Kenny Guycfe7b702017-11-14 21:04:58 +0000654 synchronized (mDataCollectionLock) {
Kenny Guy05ce8092018-01-17 13:44:20 +0000655 pw.println(" mStarted=" + mStarted);
Kenny Guycfe7b702017-11-14 21:04:58 +0000656 pw.println(" mLastSensorReadings.size=" + mLastSensorReadings.size());
Kenny Guye1674e52017-11-30 16:25:26 +0000657 if (!mLastSensorReadings.isEmpty()) {
658 pw.println(" mLastSensorReadings time span "
659 + mLastSensorReadings.peekFirst().timestamp + "->"
660 + mLastSensorReadings.peekLast().timestamp);
661 }
662 }
663 synchronized (mEventsLock) {
664 pw.println(" mEventsDirty=" + mEventsDirty);
665 pw.println(" mEvents.size=" + mEvents.size());
666 BrightnessChangeEvent[] events = mEvents.toArray();
667 for (int i = 0; i < events.length; ++i) {
668 pw.print(" " + events[i].timeStamp + ", " + events[i].userId);
Kenny Guy53d06612018-01-30 14:19:13 +0000669 pw.print(", " + events[i].lastBrightness + "->" + events[i].brightness);
670 pw.print(", isUserSetBrightness=" + events[i].isUserSetBrightness);
671 pw.print(", powerBrightnessFactor=" + events[i].powerBrightnessFactor);
672 pw.print(", isDefaultBrightnessConfig=" + events[i].isDefaultBrightnessConfig);
673 pw.print(" {");
Kenny Guye1674e52017-11-30 16:25:26 +0000674 for (int j = 0; j < events[i].luxValues.length; ++j){
675 if (j != 0) {
676 pw.print(", ");
677 }
678 pw.print("(" + events[i].luxValues[j] + "," + events[i].luxTimestamps[j] + ")");
679 }
680 pw.println("}");
681 }
Kenny Guycfe7b702017-11-14 21:04:58 +0000682 }
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000683 if (mAmbientBrightnessStatsTracker != null) {
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000684 pw.println();
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000685 mAmbientBrightnessStatsTracker.dump(pw);
686 }
687 }
688
689 public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) {
Kenny Guy637f8be2018-04-03 13:16:58 +0100690 if (mAmbientBrightnessStatsTracker != null) {
691 ArrayList<AmbientBrightnessDayStats> stats =
692 mAmbientBrightnessStatsTracker.getUserStats(
693 userId);
694 if (stats != null) {
695 return new ParceledListSlice<>(stats);
696 }
697 }
698 return ParceledListSlice.emptyList();
Kenny Guycfe7b702017-11-14 21:04:58 +0000699 }
700
Kenny Guy22bd0442017-10-26 00:15:54 +0100701 // Not allowed to keep the SensorEvent so used to copy the data we care about.
702 private static class LightData {
703 public float lux;
704 // Time in elapsedRealtimeNanos
705 public long timestamp;
706 }
707
708 private void recordSensorEvent(SensorEvent event) {
709 long horizon = mInjector.elapsedRealtimeNanos() - LUX_EVENT_HORIZON;
710 synchronized (mDataCollectionLock) {
711 if (DEBUG) {
712 Slog.v(TAG, "Sensor event " + event);
713 }
714 if (!mLastSensorReadings.isEmpty()
715 && event.timestamp < mLastSensorReadings.getLast().timestamp) {
716 // Ignore event that came out of order.
717 return;
718 }
719 LightData data = null;
720 while (!mLastSensorReadings.isEmpty()
721 && mLastSensorReadings.getFirst().timestamp < horizon) {
722 // Remove data that has fallen out of the window.
723 data = mLastSensorReadings.removeFirst();
724 }
725 // We put back the last one we removed so we know how long
726 // the first sensor reading was valid for.
727 if (data != null) {
728 mLastSensorReadings.addFirst(data);
729 }
730
731 data = new LightData();
732 data.timestamp = event.timestamp;
733 data.lux = event.values[0];
734 mLastSensorReadings.addLast(data);
735 }
736 }
737
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000738 private void recordAmbientBrightnessStats(SensorEvent event) {
739 mAmbientBrightnessStatsTracker.add(mCurrentUserId, event.values[0]);
740 }
741
Kenny Guy22bd0442017-10-26 00:15:54 +0100742 private void batteryLevelChanged(int level, int scale) {
743 synchronized (mDataCollectionLock) {
744 mLastBatteryLevel = (float) level / (float) scale;
745 }
746 }
747
748 private final class SensorListener implements SensorEventListener {
749 @Override
750 public void onSensorChanged(SensorEvent event) {
751 recordSensorEvent(event);
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000752 recordAmbientBrightnessStats(event);
Kenny Guy22bd0442017-10-26 00:15:54 +0100753 }
754
755 @Override
756 public void onAccuracyChanged(Sensor sensor, int accuracy) {
757
758 }
759 }
760
Kenny Guy3d7172c2018-03-19 14:18:23 +0000761 private final class SettingsObserver extends ContentObserver {
762 public SettingsObserver(Handler handler) {
763 super(handler);
764 }
765
766 @Override
767 public void onChange(boolean selfChange, Uri uri) {
768 if (DEBUG) {
769 Slog.v(TAG, "settings change " + uri);
770 }
771 if (mInjector.isBrightnessModeAutomatic(mContentResolver)) {
772 mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget();
773 } else {
774 mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget();
775 }
776 }
777 }
778
Kenny Guy22bd0442017-10-26 00:15:54 +0100779 private final class Receiver extends BroadcastReceiver {
780 @Override
781 public void onReceive(Context context, Intent intent) {
782 if (DEBUG) {
783 Slog.d(TAG, "Received " + intent.getAction());
784 }
785 String action = intent.getAction();
786 if (Intent.ACTION_SHUTDOWN.equals(action)) {
787 stop();
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000788 scheduleWriteBrightnessTrackerState();
Kenny Guy22bd0442017-10-26 00:15:54 +0100789 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
790 int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
791 int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
792 if (level != -1 && scale != 0) {
793 batteryLevelChanged(level, scale);
794 }
Kenny Guy689ab8f2017-11-29 12:12:06 +0000795 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
Kenny Guy3d7172c2018-03-19 14:18:23 +0000796 mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget();
Kenny Guy689ab8f2017-11-29 12:12:06 +0000797 } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
Kenny Guy3d7172c2018-03-19 14:18:23 +0000798 mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget();
Kenny Guy22bd0442017-10-26 00:15:54 +0100799 }
800 }
801 }
802
Michael Wright144aac92017-12-21 18:37:41 +0000803 private final class TrackerHandler extends Handler {
804 public TrackerHandler(Looper looper) {
805 super(looper, null, true /*async*/);
806 }
807 public void handleMessage(Message msg) {
808 switch (msg.what) {
809 case MSG_BACKGROUND_START:
810 backgroundStart((float)msg.obj /*initial brightness*/);
811 break;
812 case MSG_BRIGHTNESS_CHANGED:
Kenny Guy53d06612018-01-30 14:19:13 +0000813 BrightnessChangeValues values = (BrightnessChangeValues) msg.obj;
Michael Wright144aac92017-12-21 18:37:41 +0000814 boolean userInitiatedChange = (msg.arg1 == 1);
Kenny Guy53d06612018-01-30 14:19:13 +0000815 handleBrightnessChanged(values.brightness, userInitiatedChange,
816 values.powerBrightnessFactor, values.isUserSetBrightness,
Kenny Guy2b326bf2018-04-18 18:42:10 +0100817 values.isDefaultBrightnessConfig, values.timestamp);
Michael Wright144aac92017-12-21 18:37:41 +0000818 break;
Kenny Guy3d7172c2018-03-19 14:18:23 +0000819 case MSG_START_SENSOR_LISTENER:
820 startSensorListener();
821 break;
822 case MSG_STOP_SENSOR_LISTENER:
823 stopSensorListener();
824 break;
Michael Wright144aac92017-12-21 18:37:41 +0000825 }
826 }
827 }
828
Kenny Guy53d06612018-01-30 14:19:13 +0000829 private static class BrightnessChangeValues {
830 final float brightness;
831 final float powerBrightnessFactor;
832 final boolean isUserSetBrightness;
833 final boolean isDefaultBrightnessConfig;
Kenny Guy2b326bf2018-04-18 18:42:10 +0100834 final long timestamp;
Kenny Guy53d06612018-01-30 14:19:13 +0000835
836 BrightnessChangeValues(float brightness, float powerBrightnessFactor,
Kenny Guy2b326bf2018-04-18 18:42:10 +0100837 boolean isUserSetBrightness, boolean isDefaultBrightnessConfig,
838 long timestamp) {
Kenny Guy53d06612018-01-30 14:19:13 +0000839 this.brightness = brightness;
840 this.powerBrightnessFactor = powerBrightnessFactor;
841 this.isUserSetBrightness = isUserSetBrightness;
842 this.isDefaultBrightnessConfig = isDefaultBrightnessConfig;
Kenny Guy2b326bf2018-04-18 18:42:10 +0100843 this.timestamp = timestamp;
Kenny Guy53d06612018-01-30 14:19:13 +0000844 }
845 }
846
Kenny Guy22bd0442017-10-26 00:15:54 +0100847 @VisibleForTesting
848 static class Injector {
849 public void registerSensorListener(Context context,
Kenny Guy689ab8f2017-11-29 12:12:06 +0000850 SensorEventListener sensorListener, Handler handler) {
Kenny Guy22bd0442017-10-26 00:15:54 +0100851 SensorManager sensorManager = context.getSystemService(SensorManager.class);
852 Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
853 sensorManager.registerListener(sensorListener,
Kenny Guy689ab8f2017-11-29 12:12:06 +0000854 lightSensor, SensorManager.SENSOR_DELAY_NORMAL, handler);
Kenny Guy22bd0442017-10-26 00:15:54 +0100855 }
856
857 public void unregisterSensorListener(Context context, SensorEventListener sensorListener) {
858 SensorManager sensorManager = context.getSystemService(SensorManager.class);
859 sensorManager.unregisterListener(sensorListener);
860 }
861
Kenny Guy3d7172c2018-03-19 14:18:23 +0000862 public void registerBrightnessModeObserver(ContentResolver resolver,
863 ContentObserver settingsObserver) {
864 resolver.registerContentObserver(Settings.System.getUriFor(
865 Settings.System.SCREEN_BRIGHTNESS_MODE),
866 false, settingsObserver, UserHandle.USER_ALL);
867 }
868
869 public void unregisterBrightnessModeObserver(Context context,
870 ContentObserver settingsObserver) {
871 context.getContentResolver().unregisterContentObserver(settingsObserver);
872 }
873
Kenny Guy22bd0442017-10-26 00:15:54 +0100874 public void registerReceiver(Context context,
875 BroadcastReceiver receiver, IntentFilter filter) {
876 context.registerReceiver(receiver, filter);
877 }
878
879 public void unregisterReceiver(Context context,
880 BroadcastReceiver receiver) {
881 context.unregisterReceiver(receiver);
882 }
883
884 public Handler getBackgroundHandler() {
885 return BackgroundThread.getHandler();
886 }
887
Kenny Guy3d7172c2018-03-19 14:18:23 +0000888 public boolean isBrightnessModeAutomatic(ContentResolver resolver) {
889 return Settings.System.getIntForUser(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
890 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT)
891 == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
892 }
893
Kenny Guy22bd0442017-10-26 00:15:54 +0100894 public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
895 int userId) {
896 return Settings.Secure.getIntForUser(resolver, setting, defaultValue, userId);
897 }
898
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000899 public AtomicFile getFile(String filename) {
900 return new AtomicFile(new File(Environment.getDataSystemDeDirectory(), filename));
Kenny Guy22bd0442017-10-26 00:15:54 +0100901 }
902
903 public long currentTimeMillis() {
904 return System.currentTimeMillis();
905 }
906
907 public long elapsedRealtimeNanos() {
908 return SystemClock.elapsedRealtimeNanos();
909 }
910
911 public int getUserSerialNumber(UserManager userManager, int userId) {
912 return userManager.getUserSerialNumber(userId);
913 }
914
915 public int getUserId(UserManager userManager, int userSerialNumber) {
916 return userManager.getUserHandle(userSerialNumber);
917 }
918
Kenny Guy6c90d8a2018-02-20 16:53:27 +0000919 public int[] getProfileIds(UserManager userManager, int userId) {
920 if (userManager != null) {
921 return userManager.getProfileIds(userId, false);
922 } else {
923 return new int[]{userId};
924 }
925 }
926
Kenny Guy22bd0442017-10-26 00:15:54 +0100927 public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
928 return ActivityManager.getService().getFocusedStackInfo();
929 }
Kenny Guycfe7b702017-11-14 21:04:58 +0000930
931 public void scheduleIdleJob(Context context) {
932 BrightnessIdleJob.scheduleJob(context);
933 }
934
935 public void cancelIdleJob(Context context) {
936 BrightnessIdleJob.cancelJob(context);
937 }
Kenny Guy689ab8f2017-11-29 12:12:06 +0000938
939 public boolean isInteractive(Context context) {
940 return context.getSystemService(PowerManager.class).isInteractive();
941 }
Kenny Guy22bd0442017-10-26 00:15:54 +0100942 }
943}