Loading services/core/java/com/android/server/display/DisplayTransformManager.java +55 −28 Original line number Diff line number Diff line Loading @@ -24,6 +24,10 @@ import android.os.ServiceManager; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import java.util.Arrays; /** * Manager for applying color transformations to the display. */ Loading @@ -44,19 +48,34 @@ public class DisplayTransformManager { */ public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300; /** * Map of level -> color transformation matrix. */ @GuardedBy("mColorMatrix") private final SparseArray<float[]> mColorMatrix = new SparseArray<>(3); /** * Temporary matrix used internally by {@link #computeColorMatrixLocked()}. */ @GuardedBy("mColorMatrix") private final float[][] mTempColorMatrix = new float[2][16]; /** * Lock used for synchronize access to {@link #mDaltonizerMode}. */ private final Object mDaltonizerModeLock = new Object(); @GuardedBy("mDaltonizerModeLock") private int mDaltonizerMode = -1; /* package */ DisplayTransformManager() { } /** * Returns the color transform matrix set for a given level. * Returns a copy of the color transform matrix set for a given level. */ public float[] getColorMatrix(int key) { synchronized (mColorMatrix) { return mColorMatrix.get(key); final float[] value = mColorMatrix.get(key); return value == null ? null : Arrays.copyOf(value, value.length); } } Loading @@ -66,39 +85,44 @@ public class DisplayTransformManager { * Note: all color transforms are first composed to a single matrix in ascending order based * on level before being applied to the display. * * @param key the level used to identify and compose the color transform (low -> high) * @param level the level used to identify and compose the color transform (low -> high) * @param value the 4x4 color transform matrix (in column-major order), or {@code null} to * remove the color transform matrix associated with the provided level */ public void setColorMatrix(int key, float[] value) { public void setColorMatrix(int level, float[] value) { if (value != null && value.length != 16) { throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)" + ", actual length: " + value.length); } synchronized (mColorMatrix) { if (value != null) { mColorMatrix.put(key, value); final float[] oldValue = mColorMatrix.get(level); if (!Arrays.equals(oldValue, value)) { if (value == null) { mColorMatrix.remove(level); } else if (oldValue == null) { mColorMatrix.put(level, Arrays.copyOf(value, value.length)); } else { mColorMatrix.remove(key); System.arraycopy(value, 0, oldValue, 0, value.length); } // Update the current color transform. applyColorMatrix(computeColorMatrix()); applyColorMatrix(computeColorMatrixLocked()); } } } /** * Returns the composition of all current color matrices, or {@code null} if there are none. */ private float[] computeColorMatrix() { synchronized (mColorMatrix) { @GuardedBy("mColorMatrix") private float[] computeColorMatrixLocked() { final int count = mColorMatrix.size(); if (count == 0) { return null; } final float[][] result = new float[2][16]; final float[][] result = mTempColorMatrix; Matrix.setIdentityM(result[0], 0); for (int i = 0; i < count; i++) { float[] rhs = mColorMatrix.valueAt(i); Loading @@ -106,14 +130,15 @@ public class DisplayTransformManager { } return result[count % 2]; } } /** * Returns the current Daltonization mode. */ public int getDaltonizerMode() { synchronized (mDaltonizerModeLock) { return mDaltonizerMode; } } /** * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate Loading @@ -122,11 +147,13 @@ public class DisplayTransformManager { * @param mode the new Daltonization mode, or -1 to disable */ public void setDaltonizerMode(int mode) { synchronized (mDaltonizerModeLock) { if (mDaltonizerMode != mode) { mDaltonizerMode = mode; applyDaltonizerMode(mode); } } } /** * Propagates the provided color transformation matrix to the SurfaceFlinger. Loading services/core/java/com/android/server/display/NightDisplayService.java +89 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.server.display; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading @@ -24,11 +28,14 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.net.Uri; import android.opengl.Matrix; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings.Secure; import android.util.MathUtils; import android.util.Slog; import android.view.animation.AnimationUtils; import com.android.internal.app.NightDisplayController; import com.android.server.SystemService; Loading @@ -39,6 +46,8 @@ import com.android.server.twilight.TwilightState; import java.util.Calendar; import java.util.TimeZone; import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; /** * Tints the display at night. */ Loading @@ -58,6 +67,19 @@ public final class NightDisplayService extends SystemService 0, 0, 0, 1 }; /** * The identity matrix, used if one of the given matrices is {@code null}. */ private static final float[] MATRIX_IDENTITY = new float[16]; static { Matrix.setIdentityM(MATRIX_IDENTITY, 0); } /** * Evaluator used to animate color matrix transitions. */ private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator(); private final Handler mHandler; private int mCurrentUser = UserHandle.USER_NULL; Loading @@ -65,6 +87,7 @@ public final class NightDisplayService extends SystemService private boolean mBootCompleted; private NightDisplayController mController; private ValueAnimator mColorMatrixAnimator; private Boolean mIsActivated; private AutoMode mAutoMode; Loading Loading @@ -181,6 +204,11 @@ public final class NightDisplayService extends SystemService mAutoMode = null; } if (mColorMatrixAnimator != null) { mColorMatrixAnimator.end(); mColorMatrixAnimator = null; } mIsActivated = null; } Loading @@ -195,10 +223,49 @@ public final class NightDisplayService extends SystemService mAutoMode.onActivated(activated); } // Update the current color matrix. // Cancel the old animator if still running. if (mColorMatrixAnimator != null) { mColorMatrixAnimator.cancel(); } final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, activated ? MATRIX_NIGHT : null); final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY); final float[] to = mIsActivated ? MATRIX_NIGHT : null; mColorMatrixAnimator = ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR, from == null ? MATRIX_IDENTITY : from, to == null ? MATRIX_IDENTITY : to); mColorMatrixAnimator.setDuration(getContext().getResources() .getInteger(android.R.integer.config_longAnimTime)); mColorMatrixAnimator.setInterpolator(AnimationUtils.loadInterpolator( getContext(), android.R.interpolator.fast_out_slow_in)); mColorMatrixAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { final float[] value = (float[]) animator.getAnimatedValue(); dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, value); } }); mColorMatrixAnimator.addListener(new AnimatorListenerAdapter() { private boolean mIsCancelled; @Override public void onAnimationCancel(Animator animator) { mIsCancelled = true; } @Override public void onAnimationEnd(Animator animator) { if (!mIsCancelled) { // Ensure final color matrix is set at the end of the animation. If the // animation is cancelled then don't set the final color matrix so the new // animator can pick up from where this one left off. dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to); } mColorMatrixAnimator = null; } }); mColorMatrixAnimator.start(); } } Loading Loading @@ -394,4 +461,23 @@ public final class NightDisplayService extends SystemService updateActivated(); } } /** * Interpolates between two 4x4 color transform matrices (in column-major order). */ private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> { /** * Result matrix returned by {@link #evaluate(float, float[], float[])}. */ private final float[] mResultMatrix = new float[16]; @Override public float[] evaluate(float fraction, float[] startValue, float[] endValue) { for (int i = 0; i < mResultMatrix.length; i++) { mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction); } return mResultMatrix; } } } Loading
services/core/java/com/android/server/display/DisplayTransformManager.java +55 −28 Original line number Diff line number Diff line Loading @@ -24,6 +24,10 @@ import android.os.ServiceManager; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import java.util.Arrays; /** * Manager for applying color transformations to the display. */ Loading @@ -44,19 +48,34 @@ public class DisplayTransformManager { */ public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300; /** * Map of level -> color transformation matrix. */ @GuardedBy("mColorMatrix") private final SparseArray<float[]> mColorMatrix = new SparseArray<>(3); /** * Temporary matrix used internally by {@link #computeColorMatrixLocked()}. */ @GuardedBy("mColorMatrix") private final float[][] mTempColorMatrix = new float[2][16]; /** * Lock used for synchronize access to {@link #mDaltonizerMode}. */ private final Object mDaltonizerModeLock = new Object(); @GuardedBy("mDaltonizerModeLock") private int mDaltonizerMode = -1; /* package */ DisplayTransformManager() { } /** * Returns the color transform matrix set for a given level. * Returns a copy of the color transform matrix set for a given level. */ public float[] getColorMatrix(int key) { synchronized (mColorMatrix) { return mColorMatrix.get(key); final float[] value = mColorMatrix.get(key); return value == null ? null : Arrays.copyOf(value, value.length); } } Loading @@ -66,39 +85,44 @@ public class DisplayTransformManager { * Note: all color transforms are first composed to a single matrix in ascending order based * on level before being applied to the display. * * @param key the level used to identify and compose the color transform (low -> high) * @param level the level used to identify and compose the color transform (low -> high) * @param value the 4x4 color transform matrix (in column-major order), or {@code null} to * remove the color transform matrix associated with the provided level */ public void setColorMatrix(int key, float[] value) { public void setColorMatrix(int level, float[] value) { if (value != null && value.length != 16) { throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)" + ", actual length: " + value.length); } synchronized (mColorMatrix) { if (value != null) { mColorMatrix.put(key, value); final float[] oldValue = mColorMatrix.get(level); if (!Arrays.equals(oldValue, value)) { if (value == null) { mColorMatrix.remove(level); } else if (oldValue == null) { mColorMatrix.put(level, Arrays.copyOf(value, value.length)); } else { mColorMatrix.remove(key); System.arraycopy(value, 0, oldValue, 0, value.length); } // Update the current color transform. applyColorMatrix(computeColorMatrix()); applyColorMatrix(computeColorMatrixLocked()); } } } /** * Returns the composition of all current color matrices, or {@code null} if there are none. */ private float[] computeColorMatrix() { synchronized (mColorMatrix) { @GuardedBy("mColorMatrix") private float[] computeColorMatrixLocked() { final int count = mColorMatrix.size(); if (count == 0) { return null; } final float[][] result = new float[2][16]; final float[][] result = mTempColorMatrix; Matrix.setIdentityM(result[0], 0); for (int i = 0; i < count; i++) { float[] rhs = mColorMatrix.valueAt(i); Loading @@ -106,14 +130,15 @@ public class DisplayTransformManager { } return result[count % 2]; } } /** * Returns the current Daltonization mode. */ public int getDaltonizerMode() { synchronized (mDaltonizerModeLock) { return mDaltonizerMode; } } /** * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate Loading @@ -122,11 +147,13 @@ public class DisplayTransformManager { * @param mode the new Daltonization mode, or -1 to disable */ public void setDaltonizerMode(int mode) { synchronized (mDaltonizerModeLock) { if (mDaltonizerMode != mode) { mDaltonizerMode = mode; applyDaltonizerMode(mode); } } } /** * Propagates the provided color transformation matrix to the SurfaceFlinger. Loading
services/core/java/com/android/server/display/NightDisplayService.java +89 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.server.display; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading @@ -24,11 +28,14 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.net.Uri; import android.opengl.Matrix; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings.Secure; import android.util.MathUtils; import android.util.Slog; import android.view.animation.AnimationUtils; import com.android.internal.app.NightDisplayController; import com.android.server.SystemService; Loading @@ -39,6 +46,8 @@ import com.android.server.twilight.TwilightState; import java.util.Calendar; import java.util.TimeZone; import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; /** * Tints the display at night. */ Loading @@ -58,6 +67,19 @@ public final class NightDisplayService extends SystemService 0, 0, 0, 1 }; /** * The identity matrix, used if one of the given matrices is {@code null}. */ private static final float[] MATRIX_IDENTITY = new float[16]; static { Matrix.setIdentityM(MATRIX_IDENTITY, 0); } /** * Evaluator used to animate color matrix transitions. */ private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator(); private final Handler mHandler; private int mCurrentUser = UserHandle.USER_NULL; Loading @@ -65,6 +87,7 @@ public final class NightDisplayService extends SystemService private boolean mBootCompleted; private NightDisplayController mController; private ValueAnimator mColorMatrixAnimator; private Boolean mIsActivated; private AutoMode mAutoMode; Loading Loading @@ -181,6 +204,11 @@ public final class NightDisplayService extends SystemService mAutoMode = null; } if (mColorMatrixAnimator != null) { mColorMatrixAnimator.end(); mColorMatrixAnimator = null; } mIsActivated = null; } Loading @@ -195,10 +223,49 @@ public final class NightDisplayService extends SystemService mAutoMode.onActivated(activated); } // Update the current color matrix. // Cancel the old animator if still running. if (mColorMatrixAnimator != null) { mColorMatrixAnimator.cancel(); } final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, activated ? MATRIX_NIGHT : null); final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY); final float[] to = mIsActivated ? MATRIX_NIGHT : null; mColorMatrixAnimator = ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR, from == null ? MATRIX_IDENTITY : from, to == null ? MATRIX_IDENTITY : to); mColorMatrixAnimator.setDuration(getContext().getResources() .getInteger(android.R.integer.config_longAnimTime)); mColorMatrixAnimator.setInterpolator(AnimationUtils.loadInterpolator( getContext(), android.R.interpolator.fast_out_slow_in)); mColorMatrixAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { final float[] value = (float[]) animator.getAnimatedValue(); dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, value); } }); mColorMatrixAnimator.addListener(new AnimatorListenerAdapter() { private boolean mIsCancelled; @Override public void onAnimationCancel(Animator animator) { mIsCancelled = true; } @Override public void onAnimationEnd(Animator animator) { if (!mIsCancelled) { // Ensure final color matrix is set at the end of the animation. If the // animation is cancelled then don't set the final color matrix so the new // animator can pick up from where this one left off. dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to); } mColorMatrixAnimator = null; } }); mColorMatrixAnimator.start(); } } Loading Loading @@ -394,4 +461,23 @@ public final class NightDisplayService extends SystemService updateActivated(); } } /** * Interpolates between two 4x4 color transform matrices (in column-major order). */ private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> { /** * Result matrix returned by {@link #evaluate(float, float[], float[])}. */ private final float[] mResultMatrix = new float[16]; @Override public float[] evaluate(float fraction, float[] startValue, float[] endValue) { for (int i = 0; i < mResultMatrix.length; i++) { mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction); } return mResultMatrix; } } }