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 */ 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 */ 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 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 */ 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 */ 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