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