DisplayAdjustmentUtils.java revision e08340645d2539ab13900b5f835b84bcfe8b99e0
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 17package com.android.server.accessibility; 18 19import android.content.ContentResolver; 20import android.content.Context; 21import android.opengl.Matrix; 22import android.os.IBinder; 23import android.os.Parcel; 24import android.os.RemoteException; 25import android.os.ServiceManager; 26import android.provider.Settings; 27import android.util.Slog; 28import android.view.accessibility.AccessibilityManager; 29 30/** 31 * Utility methods for performing accessibility display adjustments. 32 */ 33class 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 boolean hasColorTransform = Settings.Secure.getIntForUser( 64 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1; 65 66 if (!hasColorTransform) { 67 hasColorTransform |= Settings.Secure.getIntForUser( 68 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1; 69 } 70 71 return hasColorTransform; 72 } 73 74 /** 75 * Applies the specified user's display color adjustments. 76 */ 77 public static void applyAdjustments(Context context, int userId) { 78 final ContentResolver cr = context.getContentResolver(); 79 float[] colorMatrix = new float[16]; 80 float[] outputMatrix = new float[16]; 81 boolean hasColorTransform = false; 82 83 Matrix.setIdentityM(colorMatrix, 0); 84 85 final boolean inversionEnabled = Settings.Secure.getIntForUser( 86 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1; 87 if (inversionEnabled) { 88 final float[] inversionMatrix = INVERSION_MATRIX_VALUE_ONLY; 89 Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0); 90 91 colorMatrix = outputMatrix; 92 outputMatrix = colorMatrix; 93 94 hasColorTransform = true; 95 } 96 97 final boolean daltonizerEnabled = Settings.Secure.getIntForUser( 98 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0; 99 if (daltonizerEnabled) { 100 final int daltonizerMode = Settings.Secure.getIntForUser(cr, 101 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, 102 userId); 103 // Monochromacy isn't supported by the native Daltonizer. 104 if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) { 105 Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, GRAYSCALE_MATRIX, 0); 106 107 final float[] temp = colorMatrix; 108 colorMatrix = outputMatrix; 109 outputMatrix = temp; 110 111 hasColorTransform = true; 112 nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); 113 } else { 114 nativeSetDaltonizerMode(daltonizerMode); 115 } 116 } else { 117 nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); 118 } 119 120 if (hasColorTransform) { 121 nativeSetColorTransform(colorMatrix); 122 } else { 123 nativeSetColorTransform(null); 124 } 125 } 126 127 /** 128 * Sets the surface flinger's Daltonization mode. This adjusts the color 129 * space to correct for or simulate various types of color blindness. 130 * 131 * @param mode new Daltonization mode 132 */ 133 private static void nativeSetDaltonizerMode(int mode) { 134 try { 135 final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); 136 if (flinger != null) { 137 final Parcel data = Parcel.obtain(); 138 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 139 data.writeInt(mode); 140 flinger.transact(1014, data, null, 0); 141 data.recycle(); 142 } 143 } catch (RemoteException ex) { 144 Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex); 145 } 146 } 147 148 /** 149 * Sets the surface flinger's color transformation as a 4x4 matrix. If the 150 * matrix is null, color transformations are disabled. 151 * 152 * @param m the float array that holds the transformation matrix, or null to 153 * disable transformation 154 */ 155 private static void nativeSetColorTransform(float[] m) { 156 try { 157 final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); 158 if (flinger != null) { 159 final Parcel data = Parcel.obtain(); 160 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 161 if (m != null) { 162 data.writeInt(1); 163 for (int i = 0; i < 16; i++) { 164 data.writeFloat(m[i]); 165 } 166 } else { 167 data.writeInt(0); 168 } 169 flinger.transact(1015, data, null, 0); 170 data.recycle(); 171 } 172 } catch (RemoteException ex) { 173 Slog.e(LOG_TAG, "Failed to set color transform", ex); 174 } 175 } 176 177} 178