diff options
| -rw-r--r-- | services/core/java/com/android/server/display/DisplayTransformManager.java | 83 | ||||
| -rw-r--r-- | services/core/java/com/android/server/display/NightDisplayService.java | 92 |
2 files changed, 144 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java index cfeae7bd6bd7..6902b1a5cd04 100644 --- a/services/core/java/com/android/server/display/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/DisplayTransformManager.java @@ -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. */ @@ -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); } } @@ -66,53 +85,59 @@ 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); - } else { - mColorMatrix.remove(key); - } + 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 { + System.arraycopy(value, 0, oldValue, 0, value.length); + } - // Update the current color transform. - applyColorMatrix(computeColorMatrix()); + // Update the current color transform. + applyColorMatrix(computeColorMatrixLocked()); + } } } /** * Returns the composition of all current color matrices, or {@code null} if there are none. */ - private float[] computeColorMatrix() { - synchronized (mColorMatrix) { - final int count = mColorMatrix.size(); - if (count == 0) { - return null; - } + @GuardedBy("mColorMatrix") + private float[] computeColorMatrixLocked() { + final int count = mColorMatrix.size(); + if (count == 0) { + return null; + } - final float[][] result = new float[2][16]; - Matrix.setIdentityM(result[0], 0); - for (int i = 0; i < count; i++) { - float[] rhs = mColorMatrix.valueAt(i); - Matrix.multiplyMM(result[(i + 1) % 2], 0, result[i % 2], 0, rhs, 0); - } - return result[count % 2]; + final float[][] result = mTempColorMatrix; + Matrix.setIdentityM(result[0], 0); + for (int i = 0; i < count; i++) { + float[] rhs = mColorMatrix.valueAt(i); + Matrix.multiplyMM(result[(i + 1) % 2], 0, result[i % 2], 0, rhs, 0); } + return result[count % 2]; } /** * Returns the current Daltonization mode. */ public int getDaltonizerMode() { - return mDaltonizerMode; + synchronized (mDaltonizerModeLock) { + return mDaltonizerMode; + } } /** @@ -122,9 +147,11 @@ public class DisplayTransformManager { * @param mode the new Daltonization mode, or -1 to disable */ public void setDaltonizerMode(int mode) { - if (mDaltonizerMode != mode) { - mDaltonizerMode = mode; - applyDaltonizerMode(mode); + synchronized (mDaltonizerModeLock) { + if (mDaltonizerMode != mode) { + mDaltonizerMode = mode; + applyDaltonizerMode(mode); + } } } diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java index 1f4ee9b2d4ea..39498a62fdcd 100644 --- a/services/core/java/com/android/server/display/NightDisplayService.java +++ b/services/core/java/com/android/server/display/NightDisplayService.java @@ -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; @@ -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; @@ -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. */ @@ -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; @@ -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; @@ -181,6 +204,11 @@ public final class NightDisplayService extends SystemService mAutoMode = null; } + if (mColorMatrixAnimator != null) { + mColorMatrixAnimator.end(); + mColorMatrixAnimator = null; + } + mIsActivated = null; } @@ -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(); } } @@ -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; + } + } } |