1 /* 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 17 package com.android.server.display; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 22 import android.annotation.Nullable; 23 import android.annotation.UserIdInt; 24 import android.app.ActivityManager; 25 import android.app.ActivityTaskManager; 26 import android.app.ActivityTaskManager.RootTaskInfo; 27 import android.content.BroadcastReceiver; 28 import android.content.ContentResolver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.ParceledListSlice; 33 import android.database.ContentObserver; 34 import android.graphics.PixelFormat; 35 import android.hardware.Sensor; 36 import android.hardware.SensorEvent; 37 import android.hardware.SensorEventListener; 38 import android.hardware.SensorManager; 39 import android.hardware.display.AmbientBrightnessDayStats; 40 import android.hardware.display.BrightnessChangeEvent; 41 import android.hardware.display.ColorDisplayManager; 42 import android.hardware.display.DisplayManager; 43 import android.hardware.display.DisplayManagerInternal; 44 import android.hardware.display.DisplayedContentSample; 45 import android.hardware.display.DisplayedContentSamplingAttributes; 46 import android.net.Uri; 47 import android.os.BatteryManager; 48 import android.os.Environment; 49 import android.os.Handler; 50 import android.os.Looper; 51 import android.os.Message; 52 import android.os.PowerManager; 53 import android.os.RemoteException; 54 import android.os.SystemClock; 55 import android.os.UserHandle; 56 import android.os.UserManager; 57 import android.provider.Settings; 58 import android.util.AtomicFile; 59 import android.util.Slog; 60 import android.util.Xml; 61 import android.view.Display; 62 63 import com.android.internal.annotations.GuardedBy; 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.os.BackgroundThread; 66 import com.android.internal.util.RingBuffer; 67 import com.android.modules.utils.TypedXmlPullParser; 68 import com.android.modules.utils.TypedXmlSerializer; 69 import com.android.server.LocalServices; 70 import com.android.server.display.utils.DebugUtils; 71 72 import libcore.io.IoUtils; 73 74 import org.xmlpull.v1.XmlPullParser; 75 import org.xmlpull.v1.XmlPullParserException; 76 77 import java.io.File; 78 import java.io.FileInputStream; 79 import java.io.FileOutputStream; 80 import java.io.IOException; 81 import java.io.InputStream; 82 import java.io.OutputStream; 83 import java.io.PrintWriter; 84 import java.text.SimpleDateFormat; 85 import java.util.ArrayList; 86 import java.util.Date; 87 import java.util.HashMap; 88 import java.util.Map; 89 import java.util.concurrent.TimeUnit; 90 91 /** 92 * Class that tracks recent brightness settings changes and stores 93 * associated information such as light sensor readings. 94 */ 95 public class BrightnessTracker { 96 97 static final String TAG = "BrightnessTracker"; 98 99 // To enable these logs, run: 100 // 'adb shell setprop persist.log.tag.BrightnessTracker DEBUG && adb reboot' 101 static final boolean DEBUG = DebugUtils.isDebuggable(TAG); 102 private static final String EVENTS_FILE = "brightness_events.xml"; 103 private static final String AMBIENT_BRIGHTNESS_STATS_FILE = "ambient_brightness_stats.xml"; 104 private static final int MAX_EVENTS = 100; 105 // Discard events when reading or writing that are older than this. 106 private static final long MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(30); 107 108 private static final String TAG_EVENTS = "events"; 109 private static final String TAG_EVENT = "event"; 110 private static final String ATTR_NITS = "nits"; 111 private static final String ATTR_TIMESTAMP = "timestamp"; 112 private static final String ATTR_PACKAGE_NAME = "packageName"; 113 private static final String ATTR_USER = "user"; 114 private static final String ATTR_UNIQUE_DISPLAY_ID = "uniqueDisplayId"; 115 private static final String ATTR_LUX = "lux"; 116 private static final String ATTR_LUX_TIMESTAMPS = "luxTimestamps"; 117 private static final String ATTR_BATTERY_LEVEL = "batteryLevel"; 118 private static final String ATTR_NIGHT_MODE = "nightMode"; 119 private static final String ATTR_COLOR_TEMPERATURE = "colorTemperature"; 120 private static final String ATTR_REDUCE_BRIGHT_COLORS = "reduceBrightColors"; 121 private static final String ATTR_REDUCE_BRIGHT_COLORS_STRENGTH = "reduceBrightColorsStrength"; 122 private static final String ATTR_REDUCE_BRIGHT_COLORS_OFFSET = "reduceBrightColorsOffset"; 123 private static final String ATTR_LAST_NITS = "lastNits"; 124 private static final String ATTR_DEFAULT_CONFIG = "defaultConfig"; 125 private static final String ATTR_POWER_SAVE = "powerSaveFactor"; 126 private static final String ATTR_USER_POINT = "userPoint"; 127 private static final String ATTR_COLOR_SAMPLE_DURATION = "colorSampleDuration"; 128 private static final String ATTR_COLOR_VALUE_BUCKETS = "colorValueBuckets"; 129 130 private static final int MSG_BACKGROUND_START = 0; 131 private static final int MSG_BRIGHTNESS_CHANGED = 1; 132 private static final int MSG_STOP_SENSOR_LISTENER = 2; 133 private static final int MSG_START_SENSOR_LISTENER = 3; 134 private static final int MSG_SHOULD_COLLECT_COLOR_SAMPLE_CHANGED = 4; 135 private static final int MSG_SENSOR_CHANGED = 5; 136 private static final int MSG_START_DISPLAY_LISTENER = 6; 137 private static final int MSG_STOP_DISPLAY_LISTENER = 7; 138 139 private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); 140 141 private static final long COLOR_SAMPLE_DURATION = TimeUnit.SECONDS.toSeconds(10); 142 // Sample chanel 2 of HSV which is the Value component. 143 private static final int COLOR_SAMPLE_COMPONENT_MASK = 0x1 << 2; 144 145 // Lock held while accessing mEvents, is held while writing events to flash. 146 private final Object mEventsLock = new Object(); 147 @GuardedBy("mEventsLock") 148 private RingBuffer<BrightnessChangeEvent> mEvents 149 = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS); 150 @GuardedBy("mEventsLock") 151 private boolean mEventsDirty; 152 153 private volatile boolean mWriteBrightnessTrackerStateScheduled; 154 155 private AmbientBrightnessStatsTracker mAmbientBrightnessStatsTracker; 156 157 private final UserManager mUserManager; 158 private final Context mContext; 159 private final ContentResolver mContentResolver; 160 private final Handler mBgHandler; 161 162 // These members should only be accessed on the mBgHandler thread. 163 private BroadcastReceiver mBroadcastReceiver; 164 private SensorListener mSensorListener; 165 private Sensor mLightSensor; 166 private SettingsObserver mSettingsObserver; 167 private final DisplayListener mDisplayListener = new DisplayListener(); 168 private boolean mDisplayListenerRegistered; 169 private boolean mIsDisplayActive; 170 private boolean mSensorRegistered; 171 private boolean mColorSamplingEnabled; 172 private int mNoFramesToSample; 173 private float mFrameRate; 174 private boolean mShouldCollectColorSample = false; 175 // End of block of members that should only be accessed on the mBgHandler thread. 176 177 private @UserIdInt int mCurrentUserId = UserHandle.USER_NULL; 178 179 // Lock held while collecting data related to brightness changes. 180 private final Object mDataCollectionLock = new Object(); 181 @GuardedBy("mDataCollectionLock") 182 private float mLastBatteryLevel = Float.NaN; 183 @GuardedBy("mDataCollectionLock") 184 private float mLastBrightness = -1; 185 @GuardedBy("mDataCollectionLock") 186 private boolean mStarted; 187 188 private final Injector mInjector; 189 BrightnessTracker(Context context, @Nullable Injector injector)190 public BrightnessTracker(Context context, @Nullable Injector injector) { 191 // Note this will be called very early in boot, other system 192 // services may not be present. 193 mContext = context; 194 mContentResolver = context.getContentResolver(); 195 if (injector != null) { 196 mInjector = injector; 197 } else { 198 mInjector = new Injector(); 199 } 200 mBgHandler = new TrackerHandler(mInjector.getBackgroundHandler().getLooper()); 201 mUserManager = mContext.getSystemService(UserManager.class); 202 } 203 204 /** 205 * Start listening for brightness slider events 206 * 207 * @param initialBrightness the initial screen brightness 208 */ start(float initialBrightness)209 public void start(float initialBrightness) { 210 if (DEBUG) { 211 Slog.d(TAG, "Start"); 212 } 213 mCurrentUserId = ActivityManager.getCurrentUser(); 214 mBgHandler.obtainMessage(MSG_BACKGROUND_START, (Float) initialBrightness).sendToTarget(); 215 } 216 217 /** 218 * Update tracker with new brightness configuration. 219 */ setShouldCollectColorSample(boolean shouldCollectColorSample)220 public void setShouldCollectColorSample(boolean shouldCollectColorSample) { 221 mBgHandler.obtainMessage(MSG_SHOULD_COLLECT_COLOR_SAMPLE_CHANGED, 222 shouldCollectColorSample).sendToTarget(); 223 } 224 backgroundStart(float initialBrightness)225 private void backgroundStart(float initialBrightness) { 226 synchronized (mDataCollectionLock) { 227 if (mStarted) { 228 return; 229 } 230 } 231 if (DEBUG) { 232 Slog.d(TAG, "Background start"); 233 } 234 readEvents(); 235 readAmbientBrightnessStats(); 236 237 mSensorListener = new SensorListener(); 238 239 mSettingsObserver = new SettingsObserver(mBgHandler); 240 mInjector.registerBrightnessModeObserver(mContentResolver, mSettingsObserver); 241 startDisplayListener(); 242 mIsDisplayActive = isDisplayActive(); 243 startSensorListener(); 244 245 final IntentFilter intentFilter = new IntentFilter(); 246 intentFilter.addAction(Intent.ACTION_SHUTDOWN); 247 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 248 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 249 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 250 mBroadcastReceiver = new Receiver(); 251 mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter); 252 253 mInjector.scheduleIdleJob(mContext); 254 synchronized (mDataCollectionLock) { 255 mLastBrightness = initialBrightness; 256 mStarted = true; 257 } 258 enableColorSampling(); 259 } 260 261 /** Stop listening for events */ stop()262 void stop() { 263 synchronized (mDataCollectionLock) { 264 if (!mStarted) { 265 return; 266 } 267 } 268 if (DEBUG) { 269 Slog.d(TAG, "Stop"); 270 } 271 mBgHandler.removeMessages(MSG_BACKGROUND_START); 272 stopDisplayListener(); 273 stopSensorListener(); 274 mInjector.unregisterSensorListener(mContext, mSensorListener); 275 mInjector.unregisterBrightnessModeObserver(mContext, mSettingsObserver); 276 mInjector.unregisterReceiver(mContext, mBroadcastReceiver); 277 mInjector.cancelIdleJob(mContext); 278 279 synchronized (mDataCollectionLock) { 280 mStarted = false; 281 } 282 disableColorSampling(); 283 } 284 onSwitchUser(@serIdInt int newUserId)285 public void onSwitchUser(@UserIdInt int newUserId) { 286 if (DEBUG) { 287 Slog.d(TAG, "Used id updated from " + mCurrentUserId + " to " + newUserId); 288 } 289 mCurrentUserId = newUserId; 290 } 291 292 /** 293 * @param userId userId to fetch data for. 294 * @param includePackage if false we will null out BrightnessChangeEvent.packageName 295 * @return List of recent {@link BrightnessChangeEvent}s 296 */ getEvents(int userId, boolean includePackage)297 public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId, boolean includePackage) { 298 BrightnessChangeEvent[] events; 299 synchronized (mEventsLock) { 300 events = mEvents.toArray(); 301 } 302 int[] profiles = mInjector.getProfileIds(mUserManager, userId); 303 Map<Integer, Boolean> toRedact = new HashMap<>(); 304 for (int i = 0; i < profiles.length; ++i) { 305 int profileId = profiles[i]; 306 // Include slider interactions when a managed profile app is in the 307 // foreground but always redact the package name. 308 boolean redact = (!includePackage) || profileId != userId; 309 toRedact.put(profiles[i], redact); 310 } 311 ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length); 312 for (int i = 0; i < events.length; ++i) { 313 Boolean redact = toRedact.get(events[i].userId); 314 if (redact != null) { 315 if (!redact) { 316 out.add(events[i]); 317 } else { 318 BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]), 319 /* redactPackage */ true); 320 out.add(event); 321 } 322 } 323 } 324 return new ParceledListSlice<>(out); 325 } 326 persistBrightnessTrackerState()327 public void persistBrightnessTrackerState() { 328 scheduleWriteBrightnessTrackerState(); 329 } 330 331 /** 332 * Notify the BrightnessTracker that the brightness of the display has changed. 333 * We pass both the user change and system changes, so that we know the starting point 334 * of the next user interaction. Only user interactions are then sent as BrightnessChangeEvents. 335 */ notifyBrightnessChanged(float brightness, boolean userInitiated, float powerBrightnessFactor, boolean wasShortTermModelActive, boolean isDefaultBrightnessConfig, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps)336 public void notifyBrightnessChanged(float brightness, boolean userInitiated, 337 float powerBrightnessFactor, boolean wasShortTermModelActive, 338 boolean isDefaultBrightnessConfig, String uniqueDisplayId, float[] luxValues, 339 long[] luxTimestamps) { 340 if (DEBUG) { 341 Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)", 342 brightness, userInitiated)); 343 } 344 Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED, 345 userInitiated ? 1 : 0, 0 /*unused*/, new BrightnessChangeValues(brightness, 346 powerBrightnessFactor, wasShortTermModelActive, isDefaultBrightnessConfig, 347 mInjector.currentTimeMillis(), uniqueDisplayId, luxValues, luxTimestamps)); 348 m.sendToTarget(); 349 } 350 351 /** 352 * Updates the light sensor to use. 353 */ setLightSensor(Sensor lightSensor)354 public void setLightSensor(Sensor lightSensor) { 355 mBgHandler.obtainMessage(MSG_SENSOR_CHANGED, 0 /*unused*/, 0/*unused*/, lightSensor) 356 .sendToTarget(); 357 } 358 handleBrightnessChanged(float brightness, boolean userInitiated, float powerBrightnessFactor, boolean wasShortTermModelActive, boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps)359 private void handleBrightnessChanged(float brightness, boolean userInitiated, 360 float powerBrightnessFactor, boolean wasShortTermModelActive, 361 boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId, 362 float[] luxValues, long[] luxTimestamps) { 363 BrightnessChangeEvent.Builder builder; 364 365 synchronized (mDataCollectionLock) { 366 if (!mStarted) { 367 // Not currently gathering brightness change information 368 return; 369 } 370 float previousBrightness = mLastBrightness; 371 mLastBrightness = brightness; 372 if (!userInitiated) { 373 // We want to record what current brightness is so that we know what the user 374 // changed it from, but if it wasn't user initiated then we don't want to record it 375 // as a BrightnessChangeEvent. 376 return; 377 } 378 379 builder = new BrightnessChangeEvent.Builder(); 380 builder.setBrightness(brightness); 381 builder.setTimeStamp(timestamp); 382 builder.setPowerBrightnessFactor(powerBrightnessFactor); 383 builder.setUserBrightnessPoint(wasShortTermModelActive); 384 builder.setIsDefaultBrightnessConfig(isDefaultBrightnessConfig); 385 builder.setUniqueDisplayId(uniqueDisplayId); 386 387 if (luxValues.length == 0) { 388 // No sensor data so ignore this. 389 return; 390 } 391 392 long[] luxTimestampsMillis = new long[luxTimestamps.length]; 393 394 // Convert lux timestamp in elapsed time to current time. 395 long currentTimeMillis = mInjector.currentTimeMillis(); 396 long elapsedTimeNanos = mInjector.elapsedRealtimeNanos(); 397 for (int i = 0; i < luxTimestamps.length; i++) { 398 luxTimestampsMillis[i] = currentTimeMillis - (TimeUnit.NANOSECONDS.toMillis( 399 elapsedTimeNanos) - luxTimestamps[i]); 400 } 401 builder.setLuxValues(luxValues); 402 builder.setLuxTimestamps(luxTimestampsMillis); 403 404 builder.setBatteryLevel(mLastBatteryLevel); 405 builder.setLastBrightness(previousBrightness); 406 } 407 408 try { 409 final RootTaskInfo focusedTask = mInjector.getFocusedStack(); 410 if (focusedTask != null && focusedTask.topActivity != null) { 411 builder.setUserId(focusedTask.userId); 412 builder.setPackageName(focusedTask.topActivity.getPackageName()); 413 } else { 414 // Ignore the event because we can't determine user / package. 415 if (DEBUG) { 416 Slog.d(TAG, "Ignoring event due to null focusedTask."); 417 } 418 return; 419 } 420 } catch (RemoteException e) { 421 // Really shouldn't be possible. 422 return; 423 } 424 425 builder.setNightMode(mInjector.isNightDisplayActivated(mContext)); 426 builder.setColorTemperature(mInjector.getNightDisplayColorTemperature(mContext)); 427 builder.setReduceBrightColors(mInjector.isReduceBrightColorsActivated(mContext)); 428 builder.setReduceBrightColorsStrength(mInjector.getReduceBrightColorsStrength(mContext)); 429 builder.setReduceBrightColorsOffset(mInjector.getReduceBrightColorsOffsetFactor(mContext) 430 * brightness); 431 432 if (mColorSamplingEnabled) { 433 DisplayedContentSample sample = mInjector.sampleColor(mNoFramesToSample); 434 if (sample != null && sample.getSampleComponent( 435 DisplayedContentSample.ColorComponent.CHANNEL2) != null) { 436 float numMillis = (sample.getNumFrames() / mFrameRate) * 1000.0f; 437 builder.setColorValues( 438 sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL2), 439 Math.round(numMillis)); 440 } 441 } 442 443 BrightnessChangeEvent event = builder.build(); 444 if (DEBUG) { 445 Slog.d(TAG, "Event: " + event.toString()); 446 } 447 synchronized (mEventsLock) { 448 mEventsDirty = true; 449 mEvents.append(event); 450 } 451 } 452 handleSensorChanged(Sensor lightSensor)453 private void handleSensorChanged(Sensor lightSensor) { 454 if (mLightSensor != lightSensor) { 455 mLightSensor = lightSensor; 456 if (lightSensor != null) { 457 mBgHandler.sendEmptyMessage(MSG_START_DISPLAY_LISTENER); 458 } else { 459 mBgHandler.sendEmptyMessage(MSG_STOP_DISPLAY_LISTENER); 460 } 461 stopSensorListener(); 462 // Attempt to restart the sensor listener. It will check to see if it should be running 463 // so there is no need to also check here. 464 startSensorListener(); 465 } 466 } 467 startSensorListener()468 private void startSensorListener() { 469 if (!mSensorRegistered 470 && mLightSensor != null 471 && mAmbientBrightnessStatsTracker != null 472 && mInjector.isInteractive(mContext) 473 && mIsDisplayActive 474 && mInjector.isBrightnessModeAutomatic(mContentResolver)) { 475 mAmbientBrightnessStatsTracker.start(); 476 mSensorRegistered = true; 477 mInjector.registerSensorListener(mContext, mSensorListener, mLightSensor, 478 mInjector.getBackgroundHandler()); 479 } 480 } 481 stopSensorListener()482 private void stopSensorListener() { 483 if (mSensorRegistered) { 484 mAmbientBrightnessStatsTracker.stop(); 485 mInjector.unregisterSensorListener(mContext, mSensorListener); 486 mSensorRegistered = false; 487 } 488 } 489 scheduleWriteBrightnessTrackerState()490 private void scheduleWriteBrightnessTrackerState() { 491 if (!mWriteBrightnessTrackerStateScheduled) { 492 mBgHandler.post(() -> { 493 mWriteBrightnessTrackerStateScheduled = false; 494 writeEvents(); 495 writeAmbientBrightnessStats(); 496 }); 497 mWriteBrightnessTrackerStateScheduled = true; 498 } 499 } 500 writeEvents()501 private void writeEvents() { 502 synchronized (mEventsLock) { 503 if (!mEventsDirty) { 504 // Nothing to write 505 return; 506 } 507 508 final AtomicFile writeTo = mInjector.getFile(EVENTS_FILE); 509 if (writeTo == null) { 510 return; 511 } 512 if (mEvents.isEmpty()) { 513 if (writeTo.exists()) { 514 writeTo.delete(); 515 } 516 mEventsDirty = false; 517 } else { 518 FileOutputStream output = null; 519 try { 520 output = writeTo.startWrite(); 521 writeEventsLocked(output); 522 writeTo.finishWrite(output); 523 mEventsDirty = false; 524 } catch (IOException e) { 525 writeTo.failWrite(output); 526 Slog.e(TAG, "Failed to write change mEvents.", e); 527 } 528 } 529 } 530 } 531 writeAmbientBrightnessStats()532 private void writeAmbientBrightnessStats() { 533 final AtomicFile writeTo = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE); 534 if (writeTo == null) { 535 return; 536 } 537 FileOutputStream output = null; 538 try { 539 output = writeTo.startWrite(); 540 mAmbientBrightnessStatsTracker.writeStats(output); 541 writeTo.finishWrite(output); 542 } catch (IOException e) { 543 writeTo.failWrite(output); 544 Slog.e(TAG, "Failed to write ambient brightness stats.", e); 545 } 546 } 547 548 // Return the path to the given file, either the new path 549 // /data/system/$filename, or the old path /data/system_de/$filename if the 550 // file exists there but not at the new path. Only use this for EVENTS_FILE 551 // and AMBIENT_BRIGHTNESS_STATS_FILE. 552 // 553 // Explanation: this service previously incorrectly stored these two files 554 // directly in /data/system_de, instead of in /data/system where they should 555 // have been. As system_server no longer has write access to 556 // /data/system_de itself, these files were moved to /data/system. To 557 // lazily migrate the files, we simply read from the old path if it exists 558 // and the new one doesn't, and always write to the new path. Note that 559 // system_server doesn't have permission to delete the old files. getFileWithLegacyFallback(String filename)560 private AtomicFile getFileWithLegacyFallback(String filename) { 561 AtomicFile file = mInjector.getFile(filename); 562 if (file != null && !file.exists()) { 563 AtomicFile legacyFile = mInjector.getLegacyFile(filename); 564 if (legacyFile != null && legacyFile.exists()) { 565 Slog.i(TAG, "Reading " + filename + " from old location"); 566 return legacyFile; 567 } 568 } 569 return file; 570 } 571 readEvents()572 private void readEvents() { 573 synchronized (mEventsLock) { 574 // Read might prune events so mark as dirty. 575 mEventsDirty = true; 576 mEvents.clear(); 577 final AtomicFile readFrom = getFileWithLegacyFallback(EVENTS_FILE); 578 if (readFrom != null && readFrom.exists()) { 579 FileInputStream input = null; 580 try { 581 input = readFrom.openRead(); 582 readEventsLocked(input); 583 } catch (IOException e) { 584 readFrom.delete(); 585 Slog.e(TAG, "Failed to read change mEvents.", e); 586 } finally { 587 IoUtils.closeQuietly(input); 588 } 589 } 590 } 591 } 592 readAmbientBrightnessStats()593 private void readAmbientBrightnessStats() { 594 mAmbientBrightnessStatsTracker = new AmbientBrightnessStatsTracker(mUserManager, null); 595 final AtomicFile readFrom = getFileWithLegacyFallback(AMBIENT_BRIGHTNESS_STATS_FILE); 596 if (readFrom != null && readFrom.exists()) { 597 FileInputStream input = null; 598 try { 599 input = readFrom.openRead(); 600 mAmbientBrightnessStatsTracker.readStats(input); 601 } catch (IOException e) { 602 readFrom.delete(); 603 Slog.e(TAG, "Failed to read ambient brightness stats.", e); 604 } finally { 605 IoUtils.closeQuietly(input); 606 } 607 } 608 } 609 610 @VisibleForTesting 611 @GuardedBy("mEventsLock") writeEventsLocked(OutputStream stream)612 void writeEventsLocked(OutputStream stream) throws IOException { 613 TypedXmlSerializer out = Xml.resolveSerializer(stream); 614 out.startDocument(null, true); 615 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 616 617 out.startTag(null, TAG_EVENTS); 618 BrightnessChangeEvent[] toWrite = mEvents.toArray(); 619 // Clear events, code below will add back the ones that are still within the time window. 620 mEvents.clear(); 621 if (DEBUG) { 622 Slog.d(TAG, "Writing events " + toWrite.length); 623 } 624 final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE; 625 for (int i = 0; i < toWrite.length; ++i) { 626 int userSerialNo = mInjector.getUserSerialNumber(mUserManager, toWrite[i].userId); 627 if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) { 628 mEvents.append(toWrite[i]); 629 out.startTag(null, TAG_EVENT); 630 out.attributeFloat(null, ATTR_NITS, toWrite[i].brightness); 631 out.attributeLong(null, ATTR_TIMESTAMP, toWrite[i].timeStamp); 632 out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName); 633 out.attributeInt(null, ATTR_USER, userSerialNo); 634 String uniqueDisplayId = toWrite[i].uniqueDisplayId; 635 if (uniqueDisplayId == null) { 636 uniqueDisplayId = ""; 637 } 638 out.attribute(null, ATTR_UNIQUE_DISPLAY_ID, uniqueDisplayId); 639 out.attributeFloat(null, ATTR_BATTERY_LEVEL, toWrite[i].batteryLevel); 640 out.attributeBoolean(null, ATTR_NIGHT_MODE, toWrite[i].nightMode); 641 out.attributeInt(null, ATTR_COLOR_TEMPERATURE, 642 toWrite[i].colorTemperature); 643 out.attributeBoolean(null, ATTR_REDUCE_BRIGHT_COLORS, 644 toWrite[i].reduceBrightColors); 645 out.attributeInt(null, ATTR_REDUCE_BRIGHT_COLORS_STRENGTH, 646 toWrite[i].reduceBrightColorsStrength); 647 out.attributeFloat(null, ATTR_REDUCE_BRIGHT_COLORS_OFFSET, 648 toWrite[i].reduceBrightColorsOffset); 649 out.attributeFloat(null, ATTR_LAST_NITS, 650 toWrite[i].lastBrightness); 651 out.attributeBoolean(null, ATTR_DEFAULT_CONFIG, 652 toWrite[i].isDefaultBrightnessConfig); 653 out.attributeFloat(null, ATTR_POWER_SAVE, 654 toWrite[i].powerBrightnessFactor); 655 out.attributeBoolean(null, ATTR_USER_POINT, 656 toWrite[i].isUserSetBrightness); 657 StringBuilder luxValues = new StringBuilder(); 658 StringBuilder luxTimestamps = new StringBuilder(); 659 for (int j = 0; j < toWrite[i].luxValues.length; ++j) { 660 if (j > 0) { 661 luxValues.append(','); 662 luxTimestamps.append(','); 663 } 664 luxValues.append(Float.toString(toWrite[i].luxValues[j])); 665 luxTimestamps.append(Long.toString(toWrite[i].luxTimestamps[j])); 666 } 667 out.attribute(null, ATTR_LUX, luxValues.toString()); 668 out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString()); 669 if (toWrite[i].colorValueBuckets != null 670 && toWrite[i].colorValueBuckets.length > 0) { 671 out.attributeLong(null, ATTR_COLOR_SAMPLE_DURATION, 672 toWrite[i].colorSampleDuration); 673 StringBuilder buckets = new StringBuilder(); 674 for (int j = 0; j < toWrite[i].colorValueBuckets.length; ++j) { 675 if (j > 0) { 676 buckets.append(','); 677 } 678 buckets.append(Long.toString(toWrite[i].colorValueBuckets[j])); 679 } 680 out.attribute(null, ATTR_COLOR_VALUE_BUCKETS, buckets.toString()); 681 } 682 out.endTag(null, TAG_EVENT); 683 } 684 } 685 out.endTag(null, TAG_EVENTS); 686 out.endDocument(); 687 stream.flush(); 688 } 689 690 @VisibleForTesting 691 @GuardedBy("mEventsLock") readEventsLocked(InputStream stream)692 void readEventsLocked(InputStream stream) throws IOException { 693 try { 694 TypedXmlPullParser parser = Xml.resolvePullParser(stream); 695 696 int type; 697 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 698 && type != XmlPullParser.START_TAG) { 699 } 700 String tag = parser.getName(); 701 if (!TAG_EVENTS.equals(tag)) { 702 throw new XmlPullParserException( 703 "Events not found in brightness tracker file " + tag); 704 } 705 706 final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE; 707 708 int outerDepth = parser.getDepth(); 709 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 710 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 711 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 712 continue; 713 } 714 tag = parser.getName(); 715 if (TAG_EVENT.equals(tag)) { 716 BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder(); 717 718 builder.setBrightness(parser.getAttributeFloat(null, ATTR_NITS)); 719 builder.setTimeStamp(parser.getAttributeLong(null, ATTR_TIMESTAMP)); 720 builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME)); 721 builder.setUserId(mInjector.getUserId(mUserManager, 722 parser.getAttributeInt(null, ATTR_USER))); 723 String uniqueDisplayId = parser.getAttributeValue(null, ATTR_UNIQUE_DISPLAY_ID); 724 if (uniqueDisplayId == null) { 725 uniqueDisplayId = ""; 726 } 727 builder.setUniqueDisplayId(uniqueDisplayId); 728 builder.setBatteryLevel(parser.getAttributeFloat(null, ATTR_BATTERY_LEVEL)); 729 builder.setNightMode(parser.getAttributeBoolean(null, ATTR_NIGHT_MODE)); 730 builder.setColorTemperature( 731 parser.getAttributeInt(null, ATTR_COLOR_TEMPERATURE)); 732 builder.setReduceBrightColors( 733 parser.getAttributeBoolean(null, ATTR_REDUCE_BRIGHT_COLORS)); 734 builder.setReduceBrightColorsStrength( 735 parser.getAttributeInt(null, ATTR_REDUCE_BRIGHT_COLORS_STRENGTH)); 736 builder.setReduceBrightColorsOffset( 737 parser.getAttributeFloat(null, ATTR_REDUCE_BRIGHT_COLORS_OFFSET)); 738 builder.setLastBrightness(parser.getAttributeFloat(null, ATTR_LAST_NITS)); 739 740 String luxValue = parser.getAttributeValue(null, ATTR_LUX); 741 String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS); 742 743 String[] luxValuesStrings = luxValue.split(","); 744 String[] luxTimestampsStrings = luxTimestamp.split(","); 745 if (luxValuesStrings.length != luxTimestampsStrings.length) { 746 continue; 747 } 748 float[] luxValues = new float[luxValuesStrings.length]; 749 long[] luxTimestamps = new long[luxValuesStrings.length]; 750 for (int i = 0; i < luxValues.length; ++i) { 751 luxValues[i] = Float.parseFloat(luxValuesStrings[i]); 752 luxTimestamps[i] = Long.parseLong(luxTimestampsStrings[i]); 753 } 754 builder.setLuxValues(luxValues); 755 builder.setLuxTimestamps(luxTimestamps); 756 757 builder.setIsDefaultBrightnessConfig( 758 parser.getAttributeBoolean(null, ATTR_DEFAULT_CONFIG, false)); 759 builder.setPowerBrightnessFactor( 760 parser.getAttributeFloat(null, ATTR_POWER_SAVE, 1.0f)); 761 builder.setUserBrightnessPoint( 762 parser.getAttributeBoolean(null, ATTR_USER_POINT, false)); 763 764 long colorSampleDuration = 765 parser.getAttributeLong(null, ATTR_COLOR_SAMPLE_DURATION, -1); 766 String colorValueBucketsString = 767 parser.getAttributeValue(null, ATTR_COLOR_VALUE_BUCKETS); 768 if (colorSampleDuration != -1 && colorValueBucketsString != null) { 769 String[] buckets = colorValueBucketsString.split(","); 770 long[] bucketValues = new long[buckets.length]; 771 for (int i = 0; i < bucketValues.length; ++i) { 772 bucketValues[i] = Long.parseLong(buckets[i]); 773 } 774 builder.setColorValues(bucketValues, colorSampleDuration); 775 } 776 777 BrightnessChangeEvent event = builder.build(); 778 if (DEBUG) { 779 Slog.i(TAG, "Read event " + event.brightness 780 + " " + event.packageName); 781 } 782 783 if (event.userId != -1 && event.timeStamp > timeCutOff 784 && event.luxValues.length > 0) { 785 mEvents.append(event); 786 } 787 } 788 } 789 } catch (NullPointerException | NumberFormatException | XmlPullParserException 790 | IOException e) { 791 // Failed to parse something, just start with an empty event log. 792 mEvents = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS); 793 Slog.e(TAG, "Failed to parse brightness event", e); 794 // Re-throw so we will delete the bad file. 795 throw new IOException("failed to parse file", e); 796 } 797 } 798 dump(final PrintWriter pw)799 public void dump(final PrintWriter pw) { 800 pw.println("BrightnessTracker state:"); 801 pw.println("------------------------"); 802 synchronized (mDataCollectionLock) { 803 pw.println(" mStarted=" + mStarted); 804 pw.println(" mLightSensor=" + mLightSensor); 805 pw.println(" mLastBatteryLevel=" + mLastBatteryLevel); 806 pw.println(" mLastBrightness=" + mLastBrightness); 807 } 808 synchronized (mEventsLock) { 809 pw.println(" mEventsDirty=" + mEventsDirty); 810 pw.println(" mEvents.size=" + mEvents.size()); 811 BrightnessChangeEvent[] events = mEvents.toArray(); 812 for (int i = 0; i < events.length; ++i) { 813 pw.print(" " + FORMAT.format(new Date(events[i].timeStamp))); 814 pw.print(", userId=" + events[i].userId); 815 pw.print(", " + events[i].lastBrightness + "->" + events[i].brightness); 816 pw.print(", isUserSetBrightness=" + events[i].isUserSetBrightness); 817 pw.print(", powerBrightnessFactor=" + events[i].powerBrightnessFactor); 818 pw.print(", isDefaultBrightnessConfig=" + events[i].isDefaultBrightnessConfig); 819 pw.print(", recent lux values="); 820 pw.print(" {"); 821 for (int j = 0; j < events[i].luxValues.length; ++j){ 822 if (j != 0) { 823 pw.print(", "); 824 } 825 pw.print("(" + events[i].luxValues[j] + "," + events[i].luxTimestamps[j] + ")"); 826 } 827 pw.println("}"); 828 } 829 } 830 pw.println(" mWriteBrightnessTrackerStateScheduled=" 831 + mWriteBrightnessTrackerStateScheduled); 832 mBgHandler.runWithScissors(() -> dumpLocal(pw), 1000); 833 if (mAmbientBrightnessStatsTracker != null) { 834 pw.println(); 835 mAmbientBrightnessStatsTracker.dump(pw); 836 } 837 } 838 dumpLocal(PrintWriter pw)839 private void dumpLocal(PrintWriter pw) { 840 pw.println(" mSensorRegistered=" + mSensorRegistered); 841 pw.println(" mColorSamplingEnabled=" + mColorSamplingEnabled); 842 pw.println(" mNoFramesToSample=" + mNoFramesToSample); 843 pw.println(" mFrameRate=" + mFrameRate); 844 pw.println(" mIsDisplayActive=" + mIsDisplayActive); 845 pw.println(" mDisplayListenerRegistered=" + mDisplayListenerRegistered); 846 } 847 enableColorSampling()848 private void enableColorSampling() { 849 if (!mInjector.isBrightnessModeAutomatic(mContentResolver) 850 || !mInjector.isInteractive(mContext) 851 || !mIsDisplayActive 852 || mColorSamplingEnabled 853 || !mShouldCollectColorSample) { 854 return; 855 } 856 857 mFrameRate = mInjector.getFrameRate(mContext); 858 if (mFrameRate <= 0) { 859 Slog.wtf(TAG, "Default display has a zero or negative framerate."); 860 return; 861 } 862 mNoFramesToSample = (int) (mFrameRate * COLOR_SAMPLE_DURATION); 863 864 DisplayedContentSamplingAttributes attributes = mInjector.getSamplingAttributes(); 865 if (DEBUG && attributes != null) { 866 Slog.d(TAG, "Color sampling" 867 + " mask=0x" + Integer.toHexString(attributes.getComponentMask()) 868 + " dataSpace=0x" + Integer.toHexString(attributes.getDataspace()) 869 + " pixelFormat=0x" + Integer.toHexString(attributes.getPixelFormat())); 870 } 871 // Do we support sampling the Value component of HSV 872 if (attributes != null && attributes.getPixelFormat() == PixelFormat.HSV_888 873 && (attributes.getComponentMask() & COLOR_SAMPLE_COMPONENT_MASK) != 0) { 874 875 mColorSamplingEnabled = mInjector.enableColorSampling(/* enable= */true, 876 mNoFramesToSample); 877 if (DEBUG) { 878 Slog.i(TAG, "turning on color sampling for " 879 + mNoFramesToSample + " frames, success=" + mColorSamplingEnabled); 880 } 881 } 882 } 883 disableColorSampling()884 private void disableColorSampling() { 885 if (!mColorSamplingEnabled) { 886 return; 887 } 888 mInjector.enableColorSampling(/* enable= */ false, /* noFrames= */ 0); 889 mColorSamplingEnabled = false; 890 if (DEBUG) { 891 Slog.i(TAG, "turning off color sampling"); 892 } 893 } 894 updateColorSampling()895 private void updateColorSampling() { 896 if (!mColorSamplingEnabled) { 897 return; 898 } 899 float frameRate = mInjector.getFrameRate(mContext); 900 if (frameRate != mFrameRate) { 901 disableColorSampling(); 902 enableColorSampling(); 903 } 904 } 905 getAmbientBrightnessStats(int userId)906 public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) { 907 if (mAmbientBrightnessStatsTracker != null) { 908 ArrayList<AmbientBrightnessDayStats> stats = 909 mAmbientBrightnessStatsTracker.getUserStats(userId); 910 if (stats != null) { 911 return new ParceledListSlice<>(stats); 912 } 913 } 914 return ParceledListSlice.emptyList(); 915 } 916 recordAmbientBrightnessStats(SensorEvent event)917 private void recordAmbientBrightnessStats(SensorEvent event) { 918 mAmbientBrightnessStatsTracker.add(mCurrentUserId, event.values[0]); 919 } 920 batteryLevelChanged(int level, int scale)921 private void batteryLevelChanged(int level, int scale) { 922 synchronized (mDataCollectionLock) { 923 mLastBatteryLevel = (float) level / (float) scale; 924 } 925 } 926 isDisplayActive()927 private boolean isDisplayActive() { 928 return Display.isActiveState(mInjector.getDisplayState(mContext)); 929 } 930 startDisplayListener()931 private void startDisplayListener() { 932 if (!mDisplayListenerRegistered && mLightSensor != null && mInjector.isInteractive(mContext) 933 && mInjector.isBrightnessModeAutomatic(mContentResolver)) { 934 mInjector.registerDisplayListener(mContext, mDisplayListener, mBgHandler); 935 mDisplayListenerRegistered = true; 936 } 937 } 938 stopDisplayListener()939 private void stopDisplayListener() { 940 if (mDisplayListenerRegistered) { 941 mInjector.unregisterDisplayListener(mContext, mDisplayListener); 942 mDisplayListenerRegistered = false; 943 } 944 } 945 946 private final class SensorListener implements SensorEventListener { 947 @Override onSensorChanged(SensorEvent event)948 public void onSensorChanged(SensorEvent event) { 949 recordAmbientBrightnessStats(event); 950 } 951 952 @Override onAccuracyChanged(Sensor sensor, int accuracy)953 public void onAccuracyChanged(Sensor sensor, int accuracy) { 954 955 } 956 } 957 958 private final class DisplayListener implements DisplayManager.DisplayListener { 959 960 @Override onDisplayAdded(int displayId)961 public void onDisplayAdded(int displayId) { 962 // Ignore 963 } 964 965 @Override onDisplayRemoved(int displayId)966 public void onDisplayRemoved(int displayId) { 967 // Ignore 968 } 969 970 @Override onDisplayChanged(int displayId)971 public void onDisplayChanged(int displayId) { 972 if (displayId == Display.DEFAULT_DISPLAY) { 973 updateColorSampling(); 974 boolean isDisplayActive = isDisplayActive(); 975 if (mIsDisplayActive != isDisplayActive) { 976 mIsDisplayActive = isDisplayActive; 977 if (isDisplayActive) { 978 mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget(); 979 } else { 980 mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget(); 981 } 982 } 983 } 984 } 985 } 986 987 private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)988 public SettingsObserver(Handler handler) { 989 super(handler); 990 } 991 992 @Override onChange(boolean selfChange, Uri uri)993 public void onChange(boolean selfChange, Uri uri) { 994 if (DEBUG) { 995 Slog.v(TAG, "settings change " + uri); 996 } 997 if (mInjector.isBrightnessModeAutomatic(mContentResolver)) { 998 mBgHandler.sendEmptyMessage(MSG_START_DISPLAY_LISTENER); 999 mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget(); 1000 } else { 1001 mBgHandler.sendEmptyMessage(MSG_STOP_DISPLAY_LISTENER); 1002 mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget(); 1003 } 1004 } 1005 } 1006 1007 private final class Receiver extends BroadcastReceiver { 1008 @Override onReceive(Context context, Intent intent)1009 public void onReceive(Context context, Intent intent) { 1010 if (DEBUG) { 1011 Slog.d(TAG, "Received " + intent.getAction()); 1012 } 1013 String action = intent.getAction(); 1014 if (Intent.ACTION_SHUTDOWN.equals(action)) { 1015 stop(); 1016 scheduleWriteBrightnessTrackerState(); 1017 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 1018 int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 1019 int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); 1020 if (level != -1 && scale != 0) { 1021 batteryLevelChanged(level, scale); 1022 } 1023 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 1024 mBgHandler.sendEmptyMessage(MSG_STOP_DISPLAY_LISTENER); 1025 mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget(); 1026 } else if (Intent.ACTION_SCREEN_ON.equals(action)) { 1027 mBgHandler.sendEmptyMessage(MSG_START_DISPLAY_LISTENER); 1028 mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget(); 1029 } 1030 } 1031 } 1032 1033 private final class TrackerHandler extends Handler { TrackerHandler(Looper looper)1034 public TrackerHandler(Looper looper) { 1035 super(looper, null, true /*async*/); 1036 } handleMessage(Message msg)1037 public void handleMessage(Message msg) { 1038 switch (msg.what) { 1039 case MSG_BACKGROUND_START: 1040 backgroundStart((float)msg.obj /*initial brightness*/); 1041 break; 1042 case MSG_BRIGHTNESS_CHANGED: 1043 BrightnessChangeValues values = (BrightnessChangeValues) msg.obj; 1044 boolean userInitiatedChange = (msg.arg1 == 1); 1045 handleBrightnessChanged(values.brightness, userInitiatedChange, 1046 values.powerBrightnessFactor, values.wasShortTermModelActive, 1047 values.isDefaultBrightnessConfig, values.timestamp, 1048 values.uniqueDisplayId, values.luxValues, values.luxTimestamps); 1049 break; 1050 case MSG_START_SENSOR_LISTENER: 1051 startSensorListener(); 1052 enableColorSampling(); 1053 break; 1054 case MSG_STOP_SENSOR_LISTENER: 1055 stopSensorListener(); 1056 disableColorSampling(); 1057 break; 1058 case MSG_SHOULD_COLLECT_COLOR_SAMPLE_CHANGED: 1059 mShouldCollectColorSample = (boolean) msg.obj; 1060 if (mShouldCollectColorSample && !mColorSamplingEnabled) { 1061 enableColorSampling(); 1062 } else if (!mShouldCollectColorSample && mColorSamplingEnabled) { 1063 disableColorSampling(); 1064 } 1065 break; 1066 case MSG_SENSOR_CHANGED: 1067 handleSensorChanged((Sensor) msg.obj); 1068 break; 1069 case MSG_START_DISPLAY_LISTENER: 1070 startDisplayListener(); 1071 break; 1072 case MSG_STOP_DISPLAY_LISTENER: 1073 stopDisplayListener(); 1074 break; 1075 } 1076 } 1077 } 1078 1079 private static class BrightnessChangeValues { 1080 public final float brightness; 1081 public final float powerBrightnessFactor; 1082 public final boolean wasShortTermModelActive; 1083 public final boolean isDefaultBrightnessConfig; 1084 public final long timestamp; 1085 public final String uniqueDisplayId; 1086 public final float[] luxValues; 1087 public final long[] luxTimestamps; 1088 BrightnessChangeValues(float brightness, float powerBrightnessFactor, boolean wasShortTermModelActive, boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps)1089 BrightnessChangeValues(float brightness, float powerBrightnessFactor, 1090 boolean wasShortTermModelActive, boolean isDefaultBrightnessConfig, 1091 long timestamp, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps) { 1092 this.brightness = brightness; 1093 this.powerBrightnessFactor = powerBrightnessFactor; 1094 this.wasShortTermModelActive = wasShortTermModelActive; 1095 this.isDefaultBrightnessConfig = isDefaultBrightnessConfig; 1096 this.timestamp = timestamp; 1097 this.uniqueDisplayId = uniqueDisplayId; 1098 this.luxValues = luxValues; 1099 this.luxTimestamps = luxTimestamps; 1100 } 1101 } 1102 1103 @VisibleForTesting 1104 static class Injector { registerSensorListener(Context context, SensorEventListener sensorListener, Sensor lightSensor, Handler handler)1105 public void registerSensorListener(Context context, 1106 SensorEventListener sensorListener, Sensor lightSensor, Handler handler) { 1107 SensorManager sensorManager = context.getSystemService(SensorManager.class); 1108 sensorManager.registerListener(sensorListener, 1109 lightSensor, SensorManager.SENSOR_DELAY_NORMAL, handler); 1110 } 1111 unregisterSensorListener(Context context, SensorEventListener sensorListener)1112 public void unregisterSensorListener(Context context, SensorEventListener sensorListener) { 1113 SensorManager sensorManager = context.getSystemService(SensorManager.class); 1114 sensorManager.unregisterListener(sensorListener); 1115 } 1116 registerBrightnessModeObserver(ContentResolver resolver, ContentObserver settingsObserver)1117 public void registerBrightnessModeObserver(ContentResolver resolver, 1118 ContentObserver settingsObserver) { 1119 resolver.registerContentObserver(Settings.System.getUriFor( 1120 Settings.System.SCREEN_BRIGHTNESS_MODE), 1121 false, settingsObserver, UserHandle.USER_ALL); 1122 } 1123 unregisterBrightnessModeObserver(Context context, ContentObserver settingsObserver)1124 public void unregisterBrightnessModeObserver(Context context, 1125 ContentObserver settingsObserver) { 1126 context.getContentResolver().unregisterContentObserver(settingsObserver); 1127 } 1128 registerReceiver(Context context, BroadcastReceiver receiver, IntentFilter filter)1129 public void registerReceiver(Context context, 1130 BroadcastReceiver receiver, IntentFilter filter) { 1131 context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED); 1132 } 1133 unregisterReceiver(Context context, BroadcastReceiver receiver)1134 public void unregisterReceiver(Context context, 1135 BroadcastReceiver receiver) { 1136 context.unregisterReceiver(receiver); 1137 } 1138 getBackgroundHandler()1139 public Handler getBackgroundHandler() { 1140 return BackgroundThread.getHandler(); 1141 } 1142 isBrightnessModeAutomatic(ContentResolver resolver)1143 public boolean isBrightnessModeAutomatic(ContentResolver resolver) { 1144 return Settings.System.getIntForUser(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, 1145 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT) 1146 == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; 1147 } 1148 getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue, int userId)1149 public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue, 1150 int userId) { 1151 return Settings.Secure.getIntForUser(resolver, setting, defaultValue, userId); 1152 } 1153 getFile(String filename)1154 public AtomicFile getFile(String filename) { 1155 return new AtomicFile(new File(Environment.getDataSystemDirectory(), filename)); 1156 } 1157 getLegacyFile(String filename)1158 public AtomicFile getLegacyFile(String filename) { 1159 return new AtomicFile(new File(Environment.getDataSystemDeDirectory(), filename)); 1160 } 1161 currentTimeMillis()1162 public long currentTimeMillis() { 1163 return System.currentTimeMillis(); 1164 } 1165 elapsedRealtimeNanos()1166 public long elapsedRealtimeNanos() { 1167 return SystemClock.elapsedRealtimeNanos(); 1168 } 1169 getUserSerialNumber(UserManager userManager, int userId)1170 public int getUserSerialNumber(UserManager userManager, int userId) { 1171 return userManager.getUserSerialNumber(userId); 1172 } 1173 getUserId(UserManager userManager, int userSerialNumber)1174 public int getUserId(UserManager userManager, int userSerialNumber) { 1175 return userManager.getUserHandle(userSerialNumber); 1176 } 1177 getProfileIds(UserManager userManager, int userId)1178 public int[] getProfileIds(UserManager userManager, int userId) { 1179 if (userManager != null) { 1180 return userManager.getProfileIds(userId, false); 1181 } else { 1182 return new int[]{userId}; 1183 } 1184 } 1185 getFocusedStack()1186 public RootTaskInfo getFocusedStack() throws RemoteException { 1187 if (UserManager.isVisibleBackgroundUsersEnabled()) { 1188 // In MUMD (Multiple Users on Multiple Displays) system, the top most focused stack 1189 // could be on the secondary display with a user signed on its display so get the 1190 // root task info only on the default display. 1191 return ActivityTaskManager.getService().getRootTaskInfoOnDisplay( 1192 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_UNDEFINED, 1193 Display.DEFAULT_DISPLAY); 1194 } 1195 return ActivityTaskManager.getService().getFocusedRootTaskInfo(); 1196 } 1197 scheduleIdleJob(Context context)1198 public void scheduleIdleJob(Context context) { 1199 BrightnessIdleJob.scheduleJob(context); 1200 } 1201 cancelIdleJob(Context context)1202 public void cancelIdleJob(Context context) { 1203 BrightnessIdleJob.cancelJob(context); 1204 } 1205 isInteractive(Context context)1206 public boolean isInteractive(Context context) { 1207 return context.getSystemService(PowerManager.class).isInteractive(); 1208 } 1209 getDisplayState(Context context)1210 public int getDisplayState(Context context) { 1211 final DisplayManager displayManager = context.getSystemService(DisplayManager.class); 1212 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 1213 return display.getState(); 1214 } 1215 getNightDisplayColorTemperature(Context context)1216 public int getNightDisplayColorTemperature(Context context) { 1217 return context.getSystemService(ColorDisplayManager.class) 1218 .getNightDisplayColorTemperature(); 1219 } 1220 isNightDisplayActivated(Context context)1221 public boolean isNightDisplayActivated(Context context) { 1222 return context.getSystemService(ColorDisplayManager.class).isNightDisplayActivated(); 1223 } 1224 getReduceBrightColorsStrength(Context context)1225 public int getReduceBrightColorsStrength(Context context) { 1226 return context.getSystemService(ColorDisplayManager.class) 1227 .getReduceBrightColorsStrength(); 1228 } 1229 getReduceBrightColorsOffsetFactor(Context context)1230 public float getReduceBrightColorsOffsetFactor(Context context) { 1231 return context.getSystemService(ColorDisplayManager.class) 1232 .getReduceBrightColorsOffsetFactor(); 1233 } 1234 isReduceBrightColorsActivated(Context context)1235 public boolean isReduceBrightColorsActivated(Context context) { 1236 return context.getSystemService(ColorDisplayManager.class) 1237 .isReduceBrightColorsActivated(); 1238 } 1239 sampleColor(int noFramesToSample)1240 public DisplayedContentSample sampleColor(int noFramesToSample) { 1241 final DisplayManagerInternal displayManagerInternal = 1242 LocalServices.getService(DisplayManagerInternal.class); 1243 return displayManagerInternal.getDisplayedContentSample( 1244 Display.DEFAULT_DISPLAY, noFramesToSample, 0); 1245 } 1246 getFrameRate(Context context)1247 public float getFrameRate(Context context) { 1248 final DisplayManager displayManager = context.getSystemService(DisplayManager.class); 1249 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 1250 return display.getRefreshRate(); 1251 } 1252 getSamplingAttributes()1253 public DisplayedContentSamplingAttributes getSamplingAttributes() { 1254 final DisplayManagerInternal displayManagerInternal = 1255 LocalServices.getService(DisplayManagerInternal.class); 1256 return displayManagerInternal.getDisplayedContentSamplingAttributes( 1257 Display.DEFAULT_DISPLAY); 1258 } 1259 enableColorSampling(boolean enable, int noFrames)1260 public boolean enableColorSampling(boolean enable, int noFrames) { 1261 final DisplayManagerInternal displayManagerInternal = 1262 LocalServices.getService(DisplayManagerInternal.class); 1263 return displayManagerInternal.setDisplayedContentSamplingEnabled( 1264 Display.DEFAULT_DISPLAY, enable, COLOR_SAMPLE_COMPONENT_MASK, noFrames); 1265 } 1266 registerDisplayListener(Context context, DisplayManager.DisplayListener listener, Handler handler)1267 public void registerDisplayListener(Context context, 1268 DisplayManager.DisplayListener listener, Handler handler) { 1269 final DisplayManager displayManager = context.getSystemService(DisplayManager.class); 1270 displayManager.registerDisplayListener(listener, handler); 1271 } 1272 unregisterDisplayListener(Context context, DisplayManager.DisplayListener listener)1273 public void unregisterDisplayListener(Context context, 1274 DisplayManager.DisplayListener listener) { 1275 final DisplayManager displayManager = context.getSystemService(DisplayManager.class); 1276 displayManager.unregisterDisplayListener(listener); 1277 } 1278 } 1279 } 1280