1f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette/* 2f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Copyright (C) 2013 The Android Open Source Project 3f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * 4f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 5f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * you may not use this file except in compliance with the License. 6f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * You may obtain a copy of the License at 7f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * 8f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 9f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * 10f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Unless required by applicable law or agreed to in writing, software 11f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 12f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * See the License for the specific language governing permissions and 14f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * limitations under the License. 15f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 16f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 17f242659afc6539f9f1104833a88e37b5f9203417Alan Viverettepackage com.android.server.accessibility; 18f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 19f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.content.ContentResolver; 20f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.content.Context; 21f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.opengl.Matrix; 22f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.os.IBinder; 23f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.os.Parcel; 24f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.os.RemoteException; 25f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.os.ServiceManager; 26f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.provider.Settings; 27f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.util.Slog; 28f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteimport android.view.accessibility.AccessibilityManager; 29f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 30f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette/** 31f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Utility methods for performing accessibility display adjustments. 32f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 33f242659afc6539f9f1104833a88e37b5f9203417Alan Viveretteclass DisplayAdjustmentUtils { 34f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName(); 35f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 36f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** Matrix and offset used for converting color to gray-scale. */ 37f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette private static final float[] GRAYSCALE_MATRIX = new float[] { 38f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette .2126f, .2126f, .2126f, 0, 39f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette .7152f, .7152f, .7152f, 0, 40f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette .0722f, .0722f, .0722f, 0, 41f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 0, 0, 0, 1 42f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette }; 43f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 446437518061fc8718590e0272ed17ea64710d2299Alan Viverette /** 456437518061fc8718590e0272ed17ea64710d2299Alan Viverette * Matrix and offset used for luminance inversion. Represents a transform 466437518061fc8718590e0272ed17ea64710d2299Alan Viverette * from RGB to YIQ color space, rotation around the Y axis by 180 degrees, 476437518061fc8718590e0272ed17ea64710d2299Alan Viverette * transform back to RGB color space, and subtraction from 1. The last row 486437518061fc8718590e0272ed17ea64710d2299Alan Viverette * represents a non-multiplied addition, see surfaceflinger's ProgramCache 496437518061fc8718590e0272ed17ea64710d2299Alan Viverette * for full implementation details. 506437518061fc8718590e0272ed17ea64710d2299Alan Viverette */ 51f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] { 526437518061fc8718590e0272ed17ea64710d2299Alan Viverette 0.402f, -0.598f, -0.599f, 0, 536437518061fc8718590e0272ed17ea64710d2299Alan Viverette -1.174f, -0.174f, -1.175f, 0, 546437518061fc8718590e0272ed17ea64710d2299Alan Viverette -0.228f, -0.228f, 0.772f, 0, 556437518061fc8718590e0272ed17ea64710d2299Alan Viverette 1, 1, 1, 1 56f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette }; 57f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 58f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** Default inversion mode for display color correction. */ 59f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette private static final int DEFAULT_DISPLAY_DALTONIZER = 60f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY; 61f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 62f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** 63f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Returns whether the specified user with has any display color 64f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * adjustments. 65f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 66f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette public static boolean hasAdjustments(Context context, int userId) { 67f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final ContentResolver cr = context.getContentResolver(); 68f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 698864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown if (Settings.Secure.getIntForUser(cr, 708864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) { 718864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown return true; 728864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown } 73f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 748864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown if (Settings.Secure.getIntForUser(cr, 758864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) { 768864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown return true; 77f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 78f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 798864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown return false; 80f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 81f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 82f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** 83f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Applies the specified user's display color adjustments. 84f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 85f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette public static void applyAdjustments(Context context, int userId) { 86f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final ContentResolver cr = context.getContentResolver(); 878864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown float[] colorMatrix = null; 88f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 898864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown if (Settings.Secure.getIntForUser(cr, 908864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) { 918864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY); 92f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 93f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 948864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown if (Settings.Secure.getIntForUser(cr, 958864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) { 96f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final int daltonizerMode = Settings.Secure.getIntForUser(cr, 97f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, 98f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette userId); 99f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette // Monochromacy isn't supported by the native Daltonizer. 100f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) { 1018864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX); 1028864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); 103f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } else { 1048864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown setDaltonizerMode(daltonizerMode); 105f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 106f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } else { 1078864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); 108f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 109f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 1108864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown setColorTransform(colorMatrix); 1118864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown } 1128864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown 1138864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown private static float[] multiply(float[] matrix, float[] other) { 1148864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown if (matrix == null) { 1158864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown return other; 116f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 1178864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown float[] result = new float[16]; 1188864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown Matrix.multiplyMM(result, 0, matrix, 0, other, 0); 1198864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown return result; 120f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 121f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 122f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** 123f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Sets the surface flinger's Daltonization mode. This adjusts the color 124f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * space to correct for or simulate various types of color blindness. 125f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * 126f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * @param mode new Daltonization mode 127f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 1288864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown private static void setDaltonizerMode(int mode) { 129f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette try { 130f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); 131f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette if (flinger != null) { 132f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final Parcel data = Parcel.obtain(); 133f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeInterfaceToken("android.ui.ISurfaceComposer"); 134f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeInt(mode); 135f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette flinger.transact(1014, data, null, 0); 136f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.recycle(); 137f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 138f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } catch (RemoteException ex) { 139f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex); 140f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 141f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 142f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 143f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette /** 144f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * Sets the surface flinger's color transformation as a 4x4 matrix. If the 145f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * matrix is null, color transformations are disabled. 146f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * 147f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * @param m the float array that holds the transformation matrix, or null to 148f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette * disable transformation 149f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette */ 1508864415e2a29daf504b52afe911eb5c5a8b03fc0Jeff Brown private static void setColorTransform(float[] m) { 151f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette try { 152f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); 153f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette if (flinger != null) { 154f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette final Parcel data = Parcel.obtain(); 155f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeInterfaceToken("android.ui.ISurfaceComposer"); 156f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette if (m != null) { 157f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeInt(1); 158f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette for (int i = 0; i < 16; i++) { 159f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeFloat(m[i]); 160f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 161f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } else { 162f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.writeInt(0); 163f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 164f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette flinger.transact(1015, data, null, 0); 165f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette data.recycle(); 166f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 167f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } catch (RemoteException ex) { 168f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette Slog.e(LOG_TAG, "Failed to set color transform", ex); 169f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 170f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette } 171f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette 172f242659afc6539f9f1104833a88e37b5f9203417Alan Viverette} 173