blob: dbbb318db63b56f222eb0ab00c7a97dcaeb2b11a [file] [log] [blame]
Justin Klaassen22eb1992016-07-11 20:52:23 -07001/*
2 * Copyright (C) 2016 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
17package com.android.server.display;
18
19import android.opengl.Matrix;
20import android.os.IBinder;
21import android.os.Parcel;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24import android.util.Slog;
25import android.util.SparseArray;
Justin Klaassen639214e2016-07-14 21:00:06 -070026import com.android.internal.annotations.GuardedBy;
27
28import java.util.Arrays;
29
Justin Klaassen22eb1992016-07-11 20:52:23 -070030/**
31 * Manager for applying color transformations to the display.
32 */
33public class DisplayTransformManager {
34
35 private static final String TAG = "DisplayTransformManager";
36
37 /**
38 * Color transform level used by Night display to tint the display red.
39 */
40 public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
41 /**
42 * Color transform level used by A11y services to make the display monochromatic.
43 */
44 public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
45 /**
46 * Color transform level used by A11y services to invert the display colors.
47 */
48 public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300;
49
Romain Guy26a2b972017-04-17 09:39:51 -070050 private static final int SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX = 1015;
51 private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014;
Romain Guy26a2b972017-04-17 09:39:51 -070052
Justin Klaassen639214e2016-07-14 21:00:06 -070053 /**
54 * Map of level -> color transformation matrix.
55 */
56 @GuardedBy("mColorMatrix")
Justin Klaassen22eb1992016-07-11 20:52:23 -070057 private final SparseArray<float[]> mColorMatrix = new SparseArray<>(3);
Justin Klaassen639214e2016-07-14 21:00:06 -070058 /**
59 * Temporary matrix used internally by {@link #computeColorMatrixLocked()}.
60 */
61 @GuardedBy("mColorMatrix")
62 private final float[][] mTempColorMatrix = new float[2][16];
Justin Klaassen22eb1992016-07-11 20:52:23 -070063
Justin Klaassen639214e2016-07-14 21:00:06 -070064 /**
65 * Lock used for synchronize access to {@link #mDaltonizerMode}.
66 */
67 private final Object mDaltonizerModeLock = new Object();
68 @GuardedBy("mDaltonizerModeLock")
Justin Klaassen22eb1992016-07-11 20:52:23 -070069 private int mDaltonizerMode = -1;
70
71 /* package */ DisplayTransformManager() {
72 }
73
74 /**
Justin Klaassen639214e2016-07-14 21:00:06 -070075 * Returns a copy of the color transform matrix set for a given level.
Justin Klaassen22eb1992016-07-11 20:52:23 -070076 */
77 public float[] getColorMatrix(int key) {
78 synchronized (mColorMatrix) {
Justin Klaassen639214e2016-07-14 21:00:06 -070079 final float[] value = mColorMatrix.get(key);
80 return value == null ? null : Arrays.copyOf(value, value.length);
Justin Klaassen22eb1992016-07-11 20:52:23 -070081 }
82 }
83
84 /**
85 * Sets and applies a current color transform matrix for a given level.
86 * <p>
87 * Note: all color transforms are first composed to a single matrix in ascending order based
88 * on level before being applied to the display.
89 *
Justin Klaassen639214e2016-07-14 21:00:06 -070090 * @param level the level used to identify and compose the color transform (low -> high)
Justin Klaassen22eb1992016-07-11 20:52:23 -070091 * @param value the 4x4 color transform matrix (in column-major order), or {@code null} to
92 * remove the color transform matrix associated with the provided level
93 */
Justin Klaassen639214e2016-07-14 21:00:06 -070094 public void setColorMatrix(int level, float[] value) {
Justin Klaassen22eb1992016-07-11 20:52:23 -070095 if (value != null && value.length != 16) {
96 throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)"
97 + ", actual length: " + value.length);
98 }
99
100 synchronized (mColorMatrix) {
Justin Klaassen639214e2016-07-14 21:00:06 -0700101 final float[] oldValue = mColorMatrix.get(level);
102 if (!Arrays.equals(oldValue, value)) {
103 if (value == null) {
104 mColorMatrix.remove(level);
105 } else if (oldValue == null) {
106 mColorMatrix.put(level, Arrays.copyOf(value, value.length));
107 } else {
108 System.arraycopy(value, 0, oldValue, 0, value.length);
109 }
Justin Klaassen22eb1992016-07-11 20:52:23 -0700110
Justin Klaassen639214e2016-07-14 21:00:06 -0700111 // Update the current color transform.
112 applyColorMatrix(computeColorMatrixLocked());
113 }
Justin Klaassen22eb1992016-07-11 20:52:23 -0700114 }
115 }
116
117 /**
118 * Returns the composition of all current color matrices, or {@code null} if there are none.
119 */
Justin Klaassen639214e2016-07-14 21:00:06 -0700120 @GuardedBy("mColorMatrix")
121 private float[] computeColorMatrixLocked() {
122 final int count = mColorMatrix.size();
123 if (count == 0) {
124 return null;
Justin Klaassen22eb1992016-07-11 20:52:23 -0700125 }
Justin Klaassen639214e2016-07-14 21:00:06 -0700126
127 final float[][] result = mTempColorMatrix;
128 Matrix.setIdentityM(result[0], 0);
129 for (int i = 0; i < count; i++) {
130 float[] rhs = mColorMatrix.valueAt(i);
131 Matrix.multiplyMM(result[(i + 1) % 2], 0, result[i % 2], 0, rhs, 0);
132 }
133 return result[count % 2];
Justin Klaassen22eb1992016-07-11 20:52:23 -0700134 }
135
136 /**
137 * Returns the current Daltonization mode.
138 */
139 public int getDaltonizerMode() {
Justin Klaassen639214e2016-07-14 21:00:06 -0700140 synchronized (mDaltonizerModeLock) {
141 return mDaltonizerMode;
142 }
Justin Klaassen22eb1992016-07-11 20:52:23 -0700143 }
144
145 /**
146 * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate
147 * various types of color blindness.
148 *
149 * @param mode the new Daltonization mode, or -1 to disable
150 */
151 public void setDaltonizerMode(int mode) {
Justin Klaassen639214e2016-07-14 21:00:06 -0700152 synchronized (mDaltonizerModeLock) {
153 if (mDaltonizerMode != mode) {
154 mDaltonizerMode = mode;
155 applyDaltonizerMode(mode);
156 }
Justin Klaassen22eb1992016-07-11 20:52:23 -0700157 }
158 }
159
160 /**
161 * Propagates the provided color transformation matrix to the SurfaceFlinger.
162 */
163 private static void applyColorMatrix(float[] m) {
164 final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
165 if (flinger != null) {
166 final Parcel data = Parcel.obtain();
167 data.writeInterfaceToken("android.ui.ISurfaceComposer");
168 if (m != null) {
169 data.writeInt(1);
170 for (int i = 0; i < 16; i++) {
171 data.writeFloat(m[i]);
172 }
173 } else {
174 data.writeInt(0);
175 }
176 try {
Romain Guy26a2b972017-04-17 09:39:51 -0700177 flinger.transact(SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX, data, null, 0);
Justin Klaassen22eb1992016-07-11 20:52:23 -0700178 } catch (RemoteException ex) {
179 Slog.e(TAG, "Failed to set color transform", ex);
180 } finally {
181 data.recycle();
182 }
183 }
184 }
185
186 /**
187 * Propagates the provided Daltonization mode to the SurfaceFlinger.
188 */
189 private static void applyDaltonizerMode(int mode) {
190 final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
191 if (flinger != null) {
192 final Parcel data = Parcel.obtain();
193 data.writeInterfaceToken("android.ui.ISurfaceComposer");
194 data.writeInt(mode);
195 try {
Romain Guy26a2b972017-04-17 09:39:51 -0700196 flinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
Justin Klaassen22eb1992016-07-11 20:52:23 -0700197 } catch (RemoteException ex) {
198 Slog.e(TAG, "Failed to set Daltonizer mode", ex);
199 } finally {
200 data.recycle();
201 }
202 }
203 }
Justin Klaassen22eb1992016-07-11 20:52:23 -0700204}