• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.accessibility;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.opengl.Matrix;
22 import android.os.IBinder;
23 import android.os.Parcel;
24 import android.os.RemoteException;
25 import android.os.ServiceManager;
26 import android.provider.Settings;
27 import android.util.Slog;
28 import android.view.accessibility.AccessibilityManager;
29 
30 /**
31  * Utility methods for performing accessibility display adjustments.
32  */
33 class DisplayAdjustmentUtils {
34     private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName();
35 
36     /** Matrix and offset used for converting color to gray-scale. */
37     private static final float[] GRAYSCALE_MATRIX = new float[] {
38         .2126f, .2126f, .2126f, 0,
39         .7152f, .7152f, .7152f, 0,
40         .0722f, .0722f, .0722f, 0,
41              0,      0,      0, 1
42     };
43 
44     /** Matrix and offset used for value-only display inversion. */
45     private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
46            0, -.5f, -.5f, 0,
47         -.5f,    0, -.5f, 0,
48         -.5f, -.5f,    0, 0,
49            1,    1,    1, 1
50     };
51 
52     /** Default inversion mode for display color correction. */
53     private static final int DEFAULT_DISPLAY_DALTONIZER =
54             AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
55 
56     /**
57      * Returns whether the specified user with has any display color
58      * adjustments.
59      */
hasAdjustments(Context context, int userId)60     public static boolean hasAdjustments(Context context, int userId) {
61         final ContentResolver cr = context.getContentResolver();
62 
63         if (Settings.Secure.getIntForUser(cr,
64                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
65             return true;
66         }
67 
68         if (Settings.Secure.getIntForUser(cr,
69                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
70             return true;
71         }
72 
73         return false;
74     }
75 
76     /**
77      * Applies the specified user's display color adjustments.
78      */
applyAdjustments(Context context, int userId)79     public static void applyAdjustments(Context context, int userId) {
80         final ContentResolver cr = context.getContentResolver();
81         float[] colorMatrix = null;
82 
83         if (Settings.Secure.getIntForUser(cr,
84                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
85             colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
86         }
87 
88         if (Settings.Secure.getIntForUser(cr,
89                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
90             final int daltonizerMode = Settings.Secure.getIntForUser(cr,
91                     Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
92                     userId);
93             // Monochromacy isn't supported by the native Daltonizer.
94             if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
95                 colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX);
96                 setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
97             } else {
98                 setDaltonizerMode(daltonizerMode);
99             }
100         } else {
101             setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
102         }
103 
104         setColorTransform(colorMatrix);
105     }
106 
multiply(float[] matrix, float[] other)107     private static float[] multiply(float[] matrix, float[] other) {
108         if (matrix == null) {
109             return other;
110         }
111         float[] result = new float[16];
112         Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
113         return result;
114     }
115 
116     /**
117      * Sets the surface flinger's Daltonization mode. This adjusts the color
118      * space to correct for or simulate various types of color blindness.
119      *
120      * @param mode new Daltonization mode
121      */
setDaltonizerMode(int mode)122     private static void setDaltonizerMode(int mode) {
123         try {
124             final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
125             if (flinger != null) {
126                 final Parcel data = Parcel.obtain();
127                 data.writeInterfaceToken("android.ui.ISurfaceComposer");
128                 data.writeInt(mode);
129                 flinger.transact(1014, data, null, 0);
130                 data.recycle();
131             }
132         } catch (RemoteException ex) {
133             Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex);
134         }
135     }
136 
137     /**
138      * Sets the surface flinger's color transformation as a 4x4 matrix. If the
139      * matrix is null, color transformations are disabled.
140      *
141      * @param m the float array that holds the transformation matrix, or null to
142      *            disable transformation
143      */
setColorTransform(float[] m)144     private static void setColorTransform(float[] m) {
145         try {
146             final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
147             if (flinger != null) {
148                 final Parcel data = Parcel.obtain();
149                 data.writeInterfaceToken("android.ui.ISurfaceComposer");
150                 if (m != null) {
151                     data.writeInt(1);
152                     for (int i = 0; i < 16; i++) {
153                         data.writeFloat(m[i]);
154                     }
155                 } else {
156                     data.writeInt(0);
157                 }
158                 flinger.transact(1015, data, null, 0);
159                 data.recycle();
160             }
161         } catch (RemoteException ex) {
162             Slog.e(LOG_TAG, "Failed to set color transform", ex);
163         }
164     }
165 
166 }
167