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