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