Loading api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -1843,7 +1843,9 @@ package android.hardware.display { field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR; field public final float batteryLevel; field public final float brightness; field public final long colorSampleDuration; field public final int colorTemperature; field @Nullable public final long[] colorValueBuckets; field public final boolean isDefaultBrightnessConfig; field public final boolean isUserSetBrightness; field public final float lastBrightness; Loading api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -660,7 +660,9 @@ package android.hardware.display { field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR; field public final float batteryLevel; field public final float brightness; field public final long colorSampleDuration; field public final int colorTemperature; field @Nullable public final long[] colorValueBuckets; field public final boolean isDefaultBrightnessConfig; field public final boolean isUserSetBrightness; field public final float lastBrightness; Loading core/java/android/hardware/display/BrightnessChangeEvent.java +42 −2 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package android.hardware.display; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** * Data about a brightness settings change. * Loading Loading @@ -72,12 +76,29 @@ public final class BrightnessChangeEvent implements Parcelable { /** Whether brightness curve includes a user brightness point */ public final boolean isUserSetBrightness; /** * Histogram counting how many times a pixel of a given value was displayed onscreen for the * Value component of HSV if the device supports color sampling, if the device does not support * color sampling the value will be null. * The buckets of the histogram are evenly weighted, the number of buckets is device specific. * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc. */ @Nullable public final long[] colorValueBuckets; /** * How many milliseconds of data are contained in the colorValueBuckets. */ public final long colorSampleDuration; /** @hide */ private BrightnessChangeEvent(float brightness, long timeStamp, String packageName, int userId, float[] luxValues, long[] luxTimestamps, float batteryLevel, float powerBrightnessFactor, boolean nightMode, int colorTemperature, float lastBrightness, boolean isDefaultBrightnessConfig, boolean isUserSetBrightness) { float lastBrightness, boolean isDefaultBrightnessConfig, boolean isUserSetBrightness, long[] colorValueBuckets, long colorSampleDuration) { this.brightness = brightness; this.timeStamp = timeStamp; this.packageName = packageName; Loading @@ -91,6 +112,8 @@ public final class BrightnessChangeEvent implements Parcelable { this.lastBrightness = lastBrightness; this.isDefaultBrightnessConfig = isDefaultBrightnessConfig; this.isUserSetBrightness = isUserSetBrightness; this.colorValueBuckets = colorValueBuckets; this.colorSampleDuration = colorSampleDuration; } /** @hide */ Loading @@ -108,6 +131,8 @@ public final class BrightnessChangeEvent implements Parcelable { this.lastBrightness = other.lastBrightness; this.isDefaultBrightnessConfig = other.isDefaultBrightnessConfig; this.isUserSetBrightness = other.isUserSetBrightness; this.colorValueBuckets = other.colorValueBuckets; this.colorSampleDuration = other.colorSampleDuration; } private BrightnessChangeEvent(Parcel source) { Loading @@ -124,6 +149,8 @@ public final class BrightnessChangeEvent implements Parcelable { lastBrightness = source.readFloat(); isDefaultBrightnessConfig = source.readBoolean(); isUserSetBrightness = source.readBoolean(); colorValueBuckets = source.createLongArray(); colorSampleDuration = source.readLong(); } public static final Creator<BrightnessChangeEvent> CREATOR = Loading Loading @@ -156,6 +183,8 @@ public final class BrightnessChangeEvent implements Parcelable { dest.writeFloat(lastBrightness); dest.writeBoolean(isDefaultBrightnessConfig); dest.writeBoolean(isUserSetBrightness); dest.writeLongArray(colorValueBuckets); dest.writeLong(colorSampleDuration); } /** @hide */ Loading @@ -173,6 +202,8 @@ public final class BrightnessChangeEvent implements Parcelable { private float mLastBrightness; private boolean mIsDefaultBrightnessConfig; private boolean mIsUserSetBrightness; private long[] mColorValueBuckets; private long mColorSampleDuration; /** {@see BrightnessChangeEvent#brightness} */ public Builder setBrightness(float brightness) { Loading Loading @@ -252,12 +283,21 @@ public final class BrightnessChangeEvent implements Parcelable { return this; } /** {@see BrightnessChangeEvent#valueBuckets} */ public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) { Objects.requireNonNull(colorValueBuckets); mColorValueBuckets = colorValueBuckets; mColorSampleDuration = colorSampleDuration; return this; } /** Builds a BrightnessChangeEvent */ public BrightnessChangeEvent build() { return new BrightnessChangeEvent(mBrightness, mTimeStamp, mPackageName, mUserId, mLuxValues, mLuxTimestamps, mBatteryLevel, mPowerBrightnessFactor, mNightMode, mColorTemperature, mLastBrightness, mIsDefaultBrightnessConfig, mIsUserSetBrightness); mIsDefaultBrightnessConfig, mIsUserSetBrightness, mColorValueBuckets, mColorSampleDuration); } } } graphics/java/android/graphics/PixelFormat.java +6 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ public class PixelFormat { public static final int RGBA_F16 = 0x16; public static final int RGBA_1010102 = 0x2B; /** @hide */ public static final int HSV_888 = 0x37; /** * @deprecated use {@link android.graphics.ImageFormat#JPEG * ImageFormat.JPEG} instead. Loading @@ -109,6 +112,7 @@ public class PixelFormat { info.bytesPerPixel = 4; break; case RGB_888: case HSV_888: info.bitsPerPixel = 24; info.bytesPerPixel = 3; break; Loading Loading @@ -227,6 +231,8 @@ public class PixelFormat { return "RGBA_F16"; case RGBA_1010102: return "RGBA_1010102"; case HSV_888: return "HSV_888"; case JPEG: return "JPEG"; default: Loading services/core/java/com/android/server/display/BrightnessTracker.java +187 −2 Original line number Diff line number Diff line Loading @@ -27,12 +27,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ParceledListSlice; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayedContentSample; import android.hardware.display.DisplayedContentSamplingAttributes; import android.net.Uri; import android.os.BatteryManager; import android.os.Environment; Loading @@ -48,6 +53,7 @@ import android.provider.Settings; import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -55,6 +61,7 @@ import com.android.internal.app.ColorDisplayController; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.RingBuffer; import com.android.server.LocalServices; import libcore.io.IoUtils; Loading Loading @@ -111,6 +118,8 @@ public class BrightnessTracker { private static final String ATTR_DEFAULT_CONFIG = "defaultConfig"; private static final String ATTR_POWER_SAVE = "powerSaveFactor"; private static final String ATTR_USER_POINT = "userPoint"; private static final String ATTR_COLOR_SAMPLE_DURATION = "colorSampleDuration"; private static final String ATTR_COLOR_VALUE_BUCKETS = "colorValueBuckets"; private static final int MSG_BACKGROUND_START = 0; private static final int MSG_BRIGHTNESS_CHANGED = 1; Loading @@ -119,6 +128,10 @@ public class BrightnessTracker { private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); private static final long COLOR_SAMPLE_DURATION = TimeUnit.SECONDS.toSeconds(10); // Sample chanel 2 of HSV which is the Value component. private static final int COLOR_SAMPLE_COMPONENT_MASK = 0x1 << 2; // Lock held while accessing mEvents, is held while writing events to flash. private final Object mEventsLock = new Object(); @GuardedBy("mEventsLock") Loading @@ -136,12 +149,16 @@ public class BrightnessTracker { private final ContentResolver mContentResolver; private final Handler mBgHandler; // mBroadcastReceiver, mSensorListener, mSettingsObserver and mSensorRegistered // should only be used on the mBgHandler thread. // These members should only be accessed on the mBgHandler thread. private BroadcastReceiver mBroadcastReceiver; private SensorListener mSensorListener; private SettingsObserver mSettingsObserver; private DisplayListener mDisplayListener; private boolean mSensorRegistered; private boolean mColorSamplingEnabled; private int mNoFramesToSample; private float mFrameRate; // End of block of members that should only be accessed on the mBgHandler thread. private @UserIdInt int mCurrentUserId = UserHandle.USER_NULL; Loading Loading @@ -208,6 +225,7 @@ public class BrightnessTracker { mLastBrightness = initialBrightness; mStarted = true; } enableColorSampling(); } /** Stop listening for events */ Loading @@ -226,6 +244,7 @@ public class BrightnessTracker { synchronized (mDataCollectionLock) { mStarted = false; } disableColorSampling(); } public void onSwitchUser(@UserIdInt int newUserId) { Loading Loading @@ -367,6 +386,17 @@ public class BrightnessTracker { builder.setColorTemperature(mInjector.getColorTemperature(mContext, UserHandle.USER_CURRENT)); if (mColorSamplingEnabled) { DisplayedContentSample sample = mInjector.sampleColor(mNoFramesToSample); if (sample != null && sample.getSampleComponent( DisplayedContentSample.ColorComponent.CHANNEL2) != null) { float numMillis = (sample.getNumFrames() / mFrameRate) * 1000.0f; builder.setColorValues( sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL2), Math.round(numMillis)); } } BrightnessChangeEvent event = builder.build(); if (DEBUG) { Slog.d(TAG, "Event " + event.brightness + " " + event.packageName); Loading Loading @@ -541,6 +571,19 @@ public class BrightnessTracker { } out.attribute(null, ATTR_LUX, luxValues.toString()); out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString()); if (toWrite[i].colorValueBuckets != null && toWrite[i].colorValueBuckets.length > 0) { out.attribute(null, ATTR_COLOR_SAMPLE_DURATION, Long.toString(toWrite[i].colorSampleDuration)); StringBuilder buckets = new StringBuilder(); for (int j = 0; j < toWrite[i].colorValueBuckets.length; ++j) { if (j > 0) { buckets.append(','); } buckets.append(Long.toString(toWrite[i].colorValueBuckets[j])); } out.attribute(null, ATTR_COLOR_VALUE_BUCKETS, buckets.toString()); } out.endTag(null, TAG_EVENT); } } Loading Loading @@ -628,6 +671,20 @@ public class BrightnessTracker { builder.setUserBrightnessPoint(Boolean.parseBoolean(userPoint)); } String colorSampleDurationString = parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION); String colorValueBucketsString = parser.getAttributeValue(null, ATTR_COLOR_VALUE_BUCKETS); if (colorSampleDurationString != null && colorValueBucketsString != null) { long colorSampleDuration = Long.parseLong(colorSampleDurationString); String[] buckets = colorValueBucketsString.split(","); long[] bucketValues = new long[buckets.length]; for (int i = 0; i < bucketValues.length; ++i) { bucketValues[i] = Long.parseLong(buckets[i]); } builder.setColorValues(bucketValues, colorSampleDuration); } BrightnessChangeEvent event = builder.build(); if (DEBUG) { Slog.i(TAG, "Read event " + event.brightness Loading Loading @@ -695,6 +752,73 @@ public class BrightnessTracker { private void dumpLocal(PrintWriter pw) { pw.println(" mSensorRegistered=" + mSensorRegistered); pw.println(" mColorSamplingEnabled=" + mColorSamplingEnabled); pw.println(" mNoFramesToSample=" + mNoFramesToSample); pw.println(" mFrameRate=" + mFrameRate); } private void enableColorSampling() { if (!mInjector.isBrightnessModeAutomatic(mContentResolver) || !mInjector.isInteractive(mContext) || mColorSamplingEnabled) { return; } mFrameRate = mInjector.getFrameRate(mContext); if (mFrameRate <= 0) { Slog.wtf(TAG, "Default display has a zero or negative framerate."); return; } mNoFramesToSample = (int) (mFrameRate * COLOR_SAMPLE_DURATION); DisplayedContentSamplingAttributes attributes = mInjector.getSamplingAttributes(); if (DEBUG && attributes != null) { Slog.d(TAG, "Color sampling" + " mask=0x" + Integer.toHexString(attributes.getComponentMask()) + " dataSpace=0x" + Integer.toHexString(attributes.getDataspace()) + " pixelFormat=0x" + Integer.toHexString(attributes.getPixelFormat())); } // Do we support sampling the Value component of HSV if (attributes != null && attributes.getPixelFormat() == PixelFormat.HSV_888 && (attributes.getComponentMask() & COLOR_SAMPLE_COMPONENT_MASK) != 0) { mColorSamplingEnabled = mInjector.enableColorSampling(/* enable= */true, mNoFramesToSample); if (DEBUG) { Slog.i(TAG, "turning on color sampling for " + mNoFramesToSample + " frames, success=" + mColorSamplingEnabled); } } if (mColorSamplingEnabled && mDisplayListener == null) { mDisplayListener = new DisplayListener(); mInjector.registerDisplayListener(mContext, mDisplayListener, mBgHandler); } } private void disableColorSampling() { if (!mColorSamplingEnabled) { return; } mInjector.enableColorSampling(/* enable= */ false, /* noFrames= */ 0); mColorSamplingEnabled = false; if (mDisplayListener != null) { mInjector.unRegisterDisplayListener(mContext, mDisplayListener); mDisplayListener = null; } if (DEBUG) { Slog.i(TAG, "turning off color sampling"); } } private void updateColorSampling() { if (!mColorSamplingEnabled) { return; } float frameRate = mInjector.getFrameRate(mContext); if (frameRate != mFrameRate) { disableColorSampling(); enableColorSampling(); } } public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) { Loading Loading @@ -768,6 +892,26 @@ public class BrightnessTracker { } } private final class DisplayListener implements DisplayManager.DisplayListener { @Override public void onDisplayAdded(int displayId) { // Ignore } @Override public void onDisplayRemoved(int displayId) { // Ignore } @Override public void onDisplayChanged(int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { updateColorSampling(); } } } private final class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler) { super(handler); Loading Loading @@ -828,9 +972,11 @@ public class BrightnessTracker { break; case MSG_START_SENSOR_LISTENER: startSensorListener(); enableColorSampling(); break; case MSG_STOP_SENSOR_LISTENER: stopSensorListener(); disableColorSampling(); break; } } Loading Loading @@ -957,5 +1103,44 @@ public class BrightnessTracker { public boolean isNightModeActive(Context context, int userId) { return new ColorDisplayController(context, userId).isActivated(); } public DisplayedContentSample sampleColor(int noFramesToSample) { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.getDisplayedContentSample( Display.DEFAULT_DISPLAY, noFramesToSample, 0); } public float getFrameRate(Context context) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); return display.getRefreshRate(); } public DisplayedContentSamplingAttributes getSamplingAttributes() { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.getDisplayedContentSamplingAttributes( Display.DEFAULT_DISPLAY); } public boolean enableColorSampling(boolean enable, int noFrames) { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.setDisplayedContentSamplingEnabled( Display.DEFAULT_DISPLAY, enable, COLOR_SAMPLE_COMPONENT_MASK, noFrames); } public void registerDisplayListener(Context context, DisplayManager.DisplayListener listener, Handler handler) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); displayManager.registerDisplayListener(listener, handler); } public void unRegisterDisplayListener(Context context, DisplayManager.DisplayListener listener) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); displayManager.unregisterDisplayListener(listener); } } } Loading
api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -1843,7 +1843,9 @@ package android.hardware.display { field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR; field public final float batteryLevel; field public final float brightness; field public final long colorSampleDuration; field public final int colorTemperature; field @Nullable public final long[] colorValueBuckets; field public final boolean isDefaultBrightnessConfig; field public final boolean isUserSetBrightness; field public final float lastBrightness; Loading
api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -660,7 +660,9 @@ package android.hardware.display { field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR; field public final float batteryLevel; field public final float brightness; field public final long colorSampleDuration; field public final int colorTemperature; field @Nullable public final long[] colorValueBuckets; field public final boolean isDefaultBrightnessConfig; field public final boolean isUserSetBrightness; field public final float lastBrightness; Loading
core/java/android/hardware/display/BrightnessChangeEvent.java +42 −2 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package android.hardware.display; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** * Data about a brightness settings change. * Loading Loading @@ -72,12 +76,29 @@ public final class BrightnessChangeEvent implements Parcelable { /** Whether brightness curve includes a user brightness point */ public final boolean isUserSetBrightness; /** * Histogram counting how many times a pixel of a given value was displayed onscreen for the * Value component of HSV if the device supports color sampling, if the device does not support * color sampling the value will be null. * The buckets of the histogram are evenly weighted, the number of buckets is device specific. * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc. */ @Nullable public final long[] colorValueBuckets; /** * How many milliseconds of data are contained in the colorValueBuckets. */ public final long colorSampleDuration; /** @hide */ private BrightnessChangeEvent(float brightness, long timeStamp, String packageName, int userId, float[] luxValues, long[] luxTimestamps, float batteryLevel, float powerBrightnessFactor, boolean nightMode, int colorTemperature, float lastBrightness, boolean isDefaultBrightnessConfig, boolean isUserSetBrightness) { float lastBrightness, boolean isDefaultBrightnessConfig, boolean isUserSetBrightness, long[] colorValueBuckets, long colorSampleDuration) { this.brightness = brightness; this.timeStamp = timeStamp; this.packageName = packageName; Loading @@ -91,6 +112,8 @@ public final class BrightnessChangeEvent implements Parcelable { this.lastBrightness = lastBrightness; this.isDefaultBrightnessConfig = isDefaultBrightnessConfig; this.isUserSetBrightness = isUserSetBrightness; this.colorValueBuckets = colorValueBuckets; this.colorSampleDuration = colorSampleDuration; } /** @hide */ Loading @@ -108,6 +131,8 @@ public final class BrightnessChangeEvent implements Parcelable { this.lastBrightness = other.lastBrightness; this.isDefaultBrightnessConfig = other.isDefaultBrightnessConfig; this.isUserSetBrightness = other.isUserSetBrightness; this.colorValueBuckets = other.colorValueBuckets; this.colorSampleDuration = other.colorSampleDuration; } private BrightnessChangeEvent(Parcel source) { Loading @@ -124,6 +149,8 @@ public final class BrightnessChangeEvent implements Parcelable { lastBrightness = source.readFloat(); isDefaultBrightnessConfig = source.readBoolean(); isUserSetBrightness = source.readBoolean(); colorValueBuckets = source.createLongArray(); colorSampleDuration = source.readLong(); } public static final Creator<BrightnessChangeEvent> CREATOR = Loading Loading @@ -156,6 +183,8 @@ public final class BrightnessChangeEvent implements Parcelable { dest.writeFloat(lastBrightness); dest.writeBoolean(isDefaultBrightnessConfig); dest.writeBoolean(isUserSetBrightness); dest.writeLongArray(colorValueBuckets); dest.writeLong(colorSampleDuration); } /** @hide */ Loading @@ -173,6 +202,8 @@ public final class BrightnessChangeEvent implements Parcelable { private float mLastBrightness; private boolean mIsDefaultBrightnessConfig; private boolean mIsUserSetBrightness; private long[] mColorValueBuckets; private long mColorSampleDuration; /** {@see BrightnessChangeEvent#brightness} */ public Builder setBrightness(float brightness) { Loading Loading @@ -252,12 +283,21 @@ public final class BrightnessChangeEvent implements Parcelable { return this; } /** {@see BrightnessChangeEvent#valueBuckets} */ public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) { Objects.requireNonNull(colorValueBuckets); mColorValueBuckets = colorValueBuckets; mColorSampleDuration = colorSampleDuration; return this; } /** Builds a BrightnessChangeEvent */ public BrightnessChangeEvent build() { return new BrightnessChangeEvent(mBrightness, mTimeStamp, mPackageName, mUserId, mLuxValues, mLuxTimestamps, mBatteryLevel, mPowerBrightnessFactor, mNightMode, mColorTemperature, mLastBrightness, mIsDefaultBrightnessConfig, mIsUserSetBrightness); mIsDefaultBrightnessConfig, mIsUserSetBrightness, mColorValueBuckets, mColorSampleDuration); } } }
graphics/java/android/graphics/PixelFormat.java +6 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ public class PixelFormat { public static final int RGBA_F16 = 0x16; public static final int RGBA_1010102 = 0x2B; /** @hide */ public static final int HSV_888 = 0x37; /** * @deprecated use {@link android.graphics.ImageFormat#JPEG * ImageFormat.JPEG} instead. Loading @@ -109,6 +112,7 @@ public class PixelFormat { info.bytesPerPixel = 4; break; case RGB_888: case HSV_888: info.bitsPerPixel = 24; info.bytesPerPixel = 3; break; Loading Loading @@ -227,6 +231,8 @@ public class PixelFormat { return "RGBA_F16"; case RGBA_1010102: return "RGBA_1010102"; case HSV_888: return "HSV_888"; case JPEG: return "JPEG"; default: Loading
services/core/java/com/android/server/display/BrightnessTracker.java +187 −2 Original line number Diff line number Diff line Loading @@ -27,12 +27,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ParceledListSlice; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayedContentSample; import android.hardware.display.DisplayedContentSamplingAttributes; import android.net.Uri; import android.os.BatteryManager; import android.os.Environment; Loading @@ -48,6 +53,7 @@ import android.provider.Settings; import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -55,6 +61,7 @@ import com.android.internal.app.ColorDisplayController; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.RingBuffer; import com.android.server.LocalServices; import libcore.io.IoUtils; Loading Loading @@ -111,6 +118,8 @@ public class BrightnessTracker { private static final String ATTR_DEFAULT_CONFIG = "defaultConfig"; private static final String ATTR_POWER_SAVE = "powerSaveFactor"; private static final String ATTR_USER_POINT = "userPoint"; private static final String ATTR_COLOR_SAMPLE_DURATION = "colorSampleDuration"; private static final String ATTR_COLOR_VALUE_BUCKETS = "colorValueBuckets"; private static final int MSG_BACKGROUND_START = 0; private static final int MSG_BRIGHTNESS_CHANGED = 1; Loading @@ -119,6 +128,10 @@ public class BrightnessTracker { private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); private static final long COLOR_SAMPLE_DURATION = TimeUnit.SECONDS.toSeconds(10); // Sample chanel 2 of HSV which is the Value component. private static final int COLOR_SAMPLE_COMPONENT_MASK = 0x1 << 2; // Lock held while accessing mEvents, is held while writing events to flash. private final Object mEventsLock = new Object(); @GuardedBy("mEventsLock") Loading @@ -136,12 +149,16 @@ public class BrightnessTracker { private final ContentResolver mContentResolver; private final Handler mBgHandler; // mBroadcastReceiver, mSensorListener, mSettingsObserver and mSensorRegistered // should only be used on the mBgHandler thread. // These members should only be accessed on the mBgHandler thread. private BroadcastReceiver mBroadcastReceiver; private SensorListener mSensorListener; private SettingsObserver mSettingsObserver; private DisplayListener mDisplayListener; private boolean mSensorRegistered; private boolean mColorSamplingEnabled; private int mNoFramesToSample; private float mFrameRate; // End of block of members that should only be accessed on the mBgHandler thread. private @UserIdInt int mCurrentUserId = UserHandle.USER_NULL; Loading Loading @@ -208,6 +225,7 @@ public class BrightnessTracker { mLastBrightness = initialBrightness; mStarted = true; } enableColorSampling(); } /** Stop listening for events */ Loading @@ -226,6 +244,7 @@ public class BrightnessTracker { synchronized (mDataCollectionLock) { mStarted = false; } disableColorSampling(); } public void onSwitchUser(@UserIdInt int newUserId) { Loading Loading @@ -367,6 +386,17 @@ public class BrightnessTracker { builder.setColorTemperature(mInjector.getColorTemperature(mContext, UserHandle.USER_CURRENT)); if (mColorSamplingEnabled) { DisplayedContentSample sample = mInjector.sampleColor(mNoFramesToSample); if (sample != null && sample.getSampleComponent( DisplayedContentSample.ColorComponent.CHANNEL2) != null) { float numMillis = (sample.getNumFrames() / mFrameRate) * 1000.0f; builder.setColorValues( sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL2), Math.round(numMillis)); } } BrightnessChangeEvent event = builder.build(); if (DEBUG) { Slog.d(TAG, "Event " + event.brightness + " " + event.packageName); Loading Loading @@ -541,6 +571,19 @@ public class BrightnessTracker { } out.attribute(null, ATTR_LUX, luxValues.toString()); out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString()); if (toWrite[i].colorValueBuckets != null && toWrite[i].colorValueBuckets.length > 0) { out.attribute(null, ATTR_COLOR_SAMPLE_DURATION, Long.toString(toWrite[i].colorSampleDuration)); StringBuilder buckets = new StringBuilder(); for (int j = 0; j < toWrite[i].colorValueBuckets.length; ++j) { if (j > 0) { buckets.append(','); } buckets.append(Long.toString(toWrite[i].colorValueBuckets[j])); } out.attribute(null, ATTR_COLOR_VALUE_BUCKETS, buckets.toString()); } out.endTag(null, TAG_EVENT); } } Loading Loading @@ -628,6 +671,20 @@ public class BrightnessTracker { builder.setUserBrightnessPoint(Boolean.parseBoolean(userPoint)); } String colorSampleDurationString = parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION); String colorValueBucketsString = parser.getAttributeValue(null, ATTR_COLOR_VALUE_BUCKETS); if (colorSampleDurationString != null && colorValueBucketsString != null) { long colorSampleDuration = Long.parseLong(colorSampleDurationString); String[] buckets = colorValueBucketsString.split(","); long[] bucketValues = new long[buckets.length]; for (int i = 0; i < bucketValues.length; ++i) { bucketValues[i] = Long.parseLong(buckets[i]); } builder.setColorValues(bucketValues, colorSampleDuration); } BrightnessChangeEvent event = builder.build(); if (DEBUG) { Slog.i(TAG, "Read event " + event.brightness Loading Loading @@ -695,6 +752,73 @@ public class BrightnessTracker { private void dumpLocal(PrintWriter pw) { pw.println(" mSensorRegistered=" + mSensorRegistered); pw.println(" mColorSamplingEnabled=" + mColorSamplingEnabled); pw.println(" mNoFramesToSample=" + mNoFramesToSample); pw.println(" mFrameRate=" + mFrameRate); } private void enableColorSampling() { if (!mInjector.isBrightnessModeAutomatic(mContentResolver) || !mInjector.isInteractive(mContext) || mColorSamplingEnabled) { return; } mFrameRate = mInjector.getFrameRate(mContext); if (mFrameRate <= 0) { Slog.wtf(TAG, "Default display has a zero or negative framerate."); return; } mNoFramesToSample = (int) (mFrameRate * COLOR_SAMPLE_DURATION); DisplayedContentSamplingAttributes attributes = mInjector.getSamplingAttributes(); if (DEBUG && attributes != null) { Slog.d(TAG, "Color sampling" + " mask=0x" + Integer.toHexString(attributes.getComponentMask()) + " dataSpace=0x" + Integer.toHexString(attributes.getDataspace()) + " pixelFormat=0x" + Integer.toHexString(attributes.getPixelFormat())); } // Do we support sampling the Value component of HSV if (attributes != null && attributes.getPixelFormat() == PixelFormat.HSV_888 && (attributes.getComponentMask() & COLOR_SAMPLE_COMPONENT_MASK) != 0) { mColorSamplingEnabled = mInjector.enableColorSampling(/* enable= */true, mNoFramesToSample); if (DEBUG) { Slog.i(TAG, "turning on color sampling for " + mNoFramesToSample + " frames, success=" + mColorSamplingEnabled); } } if (mColorSamplingEnabled && mDisplayListener == null) { mDisplayListener = new DisplayListener(); mInjector.registerDisplayListener(mContext, mDisplayListener, mBgHandler); } } private void disableColorSampling() { if (!mColorSamplingEnabled) { return; } mInjector.enableColorSampling(/* enable= */ false, /* noFrames= */ 0); mColorSamplingEnabled = false; if (mDisplayListener != null) { mInjector.unRegisterDisplayListener(mContext, mDisplayListener); mDisplayListener = null; } if (DEBUG) { Slog.i(TAG, "turning off color sampling"); } } private void updateColorSampling() { if (!mColorSamplingEnabled) { return; } float frameRate = mInjector.getFrameRate(mContext); if (frameRate != mFrameRate) { disableColorSampling(); enableColorSampling(); } } public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) { Loading Loading @@ -768,6 +892,26 @@ public class BrightnessTracker { } } private final class DisplayListener implements DisplayManager.DisplayListener { @Override public void onDisplayAdded(int displayId) { // Ignore } @Override public void onDisplayRemoved(int displayId) { // Ignore } @Override public void onDisplayChanged(int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { updateColorSampling(); } } } private final class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler) { super(handler); Loading Loading @@ -828,9 +972,11 @@ public class BrightnessTracker { break; case MSG_START_SENSOR_LISTENER: startSensorListener(); enableColorSampling(); break; case MSG_STOP_SENSOR_LISTENER: stopSensorListener(); disableColorSampling(); break; } } Loading Loading @@ -957,5 +1103,44 @@ public class BrightnessTracker { public boolean isNightModeActive(Context context, int userId) { return new ColorDisplayController(context, userId).isActivated(); } public DisplayedContentSample sampleColor(int noFramesToSample) { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.getDisplayedContentSample( Display.DEFAULT_DISPLAY, noFramesToSample, 0); } public float getFrameRate(Context context) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); return display.getRefreshRate(); } public DisplayedContentSamplingAttributes getSamplingAttributes() { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.getDisplayedContentSamplingAttributes( Display.DEFAULT_DISPLAY); } public boolean enableColorSampling(boolean enable, int noFrames) { final DisplayManagerInternal displayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); return displayManagerInternal.setDisplayedContentSamplingEnabled( Display.DEFAULT_DISPLAY, enable, COLOR_SAMPLE_COMPONENT_MASK, noFrames); } public void registerDisplayListener(Context context, DisplayManager.DisplayListener listener, Handler handler) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); displayManager.registerDisplayListener(listener, handler); } public void unRegisterDisplayListener(Context context, DisplayManager.DisplayListener listener) { final DisplayManager displayManager = context.getSystemService(DisplayManager.class); displayManager.unregisterDisplayListener(listener); } } }