From 22eb19939d815856887f1329f41aa04b397505ff Mon Sep 17 00:00:00 2001 From: Justin Klaassen Date: Mon, 11 Jul 2016 20:52:23 -0700 Subject: [PATCH] Refactor display color transforms - Removed Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, it's not desirable to persist the actual color transformation matrix. - Refactored all SurfaceFlinger transforms to DisplayTransformManager, which allows color transforms to be set independently from the a11y manager service. Bug: 30042357 Change-Id: Iefa477dedb66aac90e1218e327802a3fab6899ed --- core/java/android/provider/Settings.java | 10 - .../providers/settings/SettingsHelper.java | 1 - .../AccessibilityManagerService.java | 41 ++-- .../accessibility/DisplayAdjustmentUtils.java | 166 +++-------------- .../server/display/DisplayManagerService.java | 1 + .../display/DisplayTransformManager.java | 175 ++++++++++++++++++ .../server/display/NightDisplayService.java | 15 +- 7 files changed, 228 insertions(+), 181 deletions(-) create mode 100644 services/core/java/com/android/server/display/DisplayTransformManager.java diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5c2778d483ac9..765a3a8cd9d48 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5294,15 +5294,6 @@ public final class Settings { public static final String ACCESSIBILITY_DISPLAY_DALTONIZER = "accessibility_display_daltonizer"; - /** - * Float list that specifies the color matrix to apply to - * the display. Valid values are defined in AccessibilityManager. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_COLOR_MATRIX = - "accessibility_display_color_matrix"; - /** * Setting that specifies whether automatic click when the mouse pointer stops moving is * enabled. @@ -6334,7 +6325,6 @@ public final class Settings { USB_MASS_STORAGE_ENABLED, // moved to global ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, ACCESSIBILITY_DISPLAY_DALTONIZER, - ACCESSIBILITY_DISPLAY_COLOR_MATRIX, ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index b79ce80272318..bf48e5de1da32 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -247,7 +247,6 @@ public class SettingsHelper { return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0; case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES: case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES: - case Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX: case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER: case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE: return !TextUtils.isEmpty(Settings.Secure.getString( diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 60d33397368dc..7ebc150bb30ba 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1422,7 +1422,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { updateTouchExplorationLocked(userState); updatePerformGesturesLocked(userState); updateEnhancedWebAccessibilityLocked(userState); - updateDisplayColorAdjustmentSettingsLocked(userState); + updateDisplayDaltonizerLocked(userState); + updateDisplayInversionLocked(userState); updateMagnificationLocked(userState); updateSoftKeyboardShowModeLocked(userState); scheduleUpdateInputFilter(userState); @@ -1539,7 +1540,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState); somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState); somethingChanged |= readAutoclickEnabledSettingLocked(userState); - somethingChanged |= readDisplayColorAdjustmentSettingsLocked(userState); return somethingChanged; } @@ -1602,18 +1602,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } - private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) { - final boolean displayAdjustmentsEnabled = DisplayAdjustmentUtils.hasAdjustments(mContext, - userState.mUserId); - if (displayAdjustmentsEnabled != userState.mHasDisplayColorAdjustment) { - userState.mHasDisplayColorAdjustment = displayAdjustmentsEnabled; - return true; - } - // If display adjustment is enabled, always assume there was a change in - // the adjustment settings. - return displayAdjustmentsEnabled; - } - private boolean readHighTextContrastEnabledSettingLocked(UserState userState) { final boolean highTextContrastEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), @@ -1730,8 +1718,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } - private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) { - DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId); + private void updateDisplayDaltonizerLocked(UserState userState) { + DisplayAdjustmentUtils.applyDaltonizerSetting(mContext, userState.mUserId); + } + + private void updateDisplayInversionLocked(UserState userState) { + DisplayAdjustmentUtils.applyInversionSetting(mContext, userState.mUserId); } private void updateMagnificationLocked(UserState userState) { @@ -4184,7 +4176,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean mIsAutoclickEnabled; public boolean mIsPerformGesturesEnabled; public boolean mIsFilterKeyEventsEnabled; - public boolean mHasDisplayColorAdjustment; public boolean mAccessibilityFocusOnlyInActiveWindow; private Service mUiAutomationService; @@ -4300,9 +4291,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER); - private final Uri mDisplayColorMatrixUri = Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX); - private final Uri mHighTextContrastUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED); @@ -4333,8 +4321,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL); - contentResolver.registerContentObserver( - mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mHighTextContrastUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( @@ -4377,14 +4363,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) { onUserStateChangedLocked(userState); } - } else if (mDisplayInversionEnabledUri.equals(uri) - || mDisplayDaltonizerEnabledUri.equals(uri) + } else if (mDisplayDaltonizerEnabledUri.equals(uri) || mDisplayDaltonizerUri.equals(uri)) { - if (readDisplayColorAdjustmentSettingsLocked(userState)) { - updateDisplayColorAdjustmentSettingsLocked(userState); - } - } else if (mDisplayColorMatrixUri.equals(uri)) { - updateDisplayColorAdjustmentSettingsLocked(userState); + updateDisplayDaltonizerLocked(userState); + } else if (mDisplayInversionEnabledUri.equals(uri)) { + updateDisplayInversionLocked(userState); } else if (mHighTextContrastUri.equals(uri)) { if (readHighTextContrastEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java index e1f3cd8dc40c0..15329461a811d 100644 --- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java +++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java @@ -18,23 +18,23 @@ package com.android.server.accessibility; import android.content.ContentResolver; import android.content.Context; -import android.opengl.Matrix; -import android.os.IBinder; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.util.Slog; +import android.provider.Settings.Secure; import android.view.accessibility.AccessibilityManager; +import com.android.server.LocalServices; +import com.android.server.display.DisplayTransformManager; + /** * Utility methods for performing accessibility display adjustments. */ class DisplayAdjustmentUtils { - private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName(); + + /** Default inversion mode for display color correction. */ + private static final int DEFAULT_DISPLAY_DALTONIZER = + AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY; /** Matrix and offset used for converting color to gray-scale. */ - private static final float[] GRAYSCALE_MATRIX = new float[] { + private static final float[] MATRIX_GRAYSCALE = new float[] { .2126f, .2126f, .2126f, 0, .7152f, .7152f, .7152f, 0, .0722f, .0722f, .0722f, 0, @@ -48,150 +48,44 @@ class DisplayAdjustmentUtils { * represents a non-multiplied addition, see surfaceflinger's ProgramCache * for full implementation details. */ - private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] { + private static final float[] MATRIX_INVERT_COLOR = new float[] { 0.402f, -0.598f, -0.599f, 0, -1.174f, -0.174f, -1.175f, 0, -0.228f, -0.228f, 0.772f, 0, 1, 1, 1, 1 }; - /** Default inversion mode for display color correction. */ - private static final int DEFAULT_DISPLAY_DALTONIZER = - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY; - - /** - * Returns whether the specified user with has any display color - * adjustments. - */ - public static boolean hasAdjustments(Context context, int userId) { + public static void applyDaltonizerSetting(Context context, int userId) { final ContentResolver cr = context.getContentResolver(); + final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - if (Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) { - return true; + int daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED; + if (Secure.getIntForUser(cr, + Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) { + daltonizerMode = Secure.getIntForUser(cr, + Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId); } - if (Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) { - return true; + float[] grayscaleMatrix = null; + if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) { + // Monochromacy isn't supported by the native Daltonizer. + grayscaleMatrix = MATRIX_GRAYSCALE; + daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED; } - - return false; + dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, grayscaleMatrix); + dtm.setDaltonizerMode(daltonizerMode); } /** * Applies the specified user's display color adjustments. */ - public static void applyAdjustments(Context context, int userId) { + public static void applyInversionSetting(Context context, int userId) { final ContentResolver cr = context.getContentResolver(); - float[] colorMatrix = null; + final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - if (Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) { - colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY); - } - - if (Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) { - final int daltonizerMode = Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, - userId); - // Monochromacy isn't supported by the native Daltonizer. - if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) { - colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX); - setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); - } else { - setDaltonizerMode(daltonizerMode); - } - } else { - setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); - } - - String matrix = Settings.Secure.getStringForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, userId); - if (matrix != null) { - final float[] userMatrix = get4x4Matrix(matrix); - if (userMatrix != null) { - colorMatrix = multiply(colorMatrix, userMatrix); - } - } - - setColorTransform(colorMatrix); + final boolean invertColors = Secure.getIntForUser(cr, + Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0; + dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR, + invertColors ? MATRIX_INVERT_COLOR : null); } - - private static float[] get4x4Matrix(String matrix) { - String[] strValues = matrix.split(","); - if (strValues.length != 16) { - return null; - } - float[] values = new float[strValues.length]; - try { - for (int i = 0; i < values.length; i++) { - values[i] = Float.parseFloat(strValues[i]); - } - } catch (java.lang.NumberFormatException ex) { - return null; - } - return values; - } - - private static float[] multiply(float[] matrix, float[] other) { - if (matrix == null) { - return other; - } - float[] result = new float[16]; - Matrix.multiplyMM(result, 0, matrix, 0, other, 0); - return result; - } - - /** - * Sets the surface flinger's Daltonization mode. This adjusts the color - * space to correct for or simulate various types of color blindness. - * - * @param mode new Daltonization mode - */ - private static void setDaltonizerMode(int mode) { - try { - final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); - if (flinger != null) { - final Parcel data = Parcel.obtain(); - data.writeInterfaceToken("android.ui.ISurfaceComposer"); - data.writeInt(mode); - flinger.transact(1014, data, null, 0); - data.recycle(); - } - } catch (RemoteException ex) { - Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex); - } - } - - /** - * Sets the surface flinger's color transformation as a 4x4 matrix. If the - * matrix is null, color transformations are disabled. - * - * @param m the float array that holds the transformation matrix, or null to - * disable transformation - */ - private static void setColorTransform(float[] m) { - try { - final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); - if (flinger != null) { - final Parcel data = Parcel.obtain(); - data.writeInterfaceToken("android.ui.ISurfaceComposer"); - if (m != null) { - data.writeInt(1); - for (int i = 0; i < 16; i++) { - data.writeFloat(m[i]); - } - } else { - data.writeInt(0); - } - flinger.transact(1015, data, null, 0); - data.recycle(); - } - } catch (RemoteException ex) { - Slog.e(LOG_TAG, "Failed to set color transform", ex); - } - } - } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 6a6570b97205c..fec7ed1ff998e 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -244,6 +244,7 @@ public final class DisplayManagerService extends SystemService { publishBinderService(Context.DISPLAY_SERVICE, new BinderService(), true /*allowIsolated*/); publishLocalService(DisplayManagerInternal.class, new LocalService()); + publishLocalService(DisplayTransformManager.class, new DisplayTransformManager()); } @Override diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java new file mode 100644 index 0000000000000..cfeae7bd6bd75 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayTransformManager.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import android.opengl.Matrix; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import android.util.SparseArray; + +/** + * Manager for applying color transformations to the display. + */ +public class DisplayTransformManager { + + private static final String TAG = "DisplayTransformManager"; + + /** + * Color transform level used by Night display to tint the display red. + */ + public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100; + /** + * Color transform level used by A11y services to make the display monochromatic. + */ + public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200; + /** + * Color transform level used by A11y services to invert the display colors. + */ + public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300; + + private final SparseArray mColorMatrix = new SparseArray<>(3); + + private int mDaltonizerMode = -1; + + /* package */ DisplayTransformManager() { + } + + /** + * Returns the color transform matrix set for a given level. + */ + public float[] getColorMatrix(int key) { + synchronized (mColorMatrix) { + return mColorMatrix.get(key); + } + } + + /** + * Sets and applies a current color transform matrix for a given level. + *

+ * Note: all color transforms are first composed to a single matrix in ascending order based + * on level before being applied to the display. + * + * @param key the level used to identify and compose the color transform (low -> high) + * @param value the 4x4 color transform matrix (in column-major order), or {@code null} to + * remove the color transform matrix associated with the provided level + */ + public void setColorMatrix(int key, float[] value) { + if (value != null && value.length != 16) { + throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)" + + ", actual length: " + value.length); + } + + synchronized (mColorMatrix) { + if (value != null) { + mColorMatrix.put(key, value); + } else { + mColorMatrix.remove(key); + } + + // Update the current color transform. + applyColorMatrix(computeColorMatrix()); + } + } + + /** + * Returns the composition of all current color matrices, or {@code null} if there are none. + */ + private float[] computeColorMatrix() { + synchronized (mColorMatrix) { + final int count = mColorMatrix.size(); + if (count == 0) { + return null; + } + + final float[][] result = new float[2][16]; + Matrix.setIdentityM(result[0], 0); + for (int i = 0; i < count; i++) { + float[] rhs = mColorMatrix.valueAt(i); + Matrix.multiplyMM(result[(i + 1) % 2], 0, result[i % 2], 0, rhs, 0); + } + return result[count % 2]; + } + } + + /** + * Returns the current Daltonization mode. + */ + public int getDaltonizerMode() { + return mDaltonizerMode; + } + + /** + * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate + * various types of color blindness. + * + * @param mode the new Daltonization mode, or -1 to disable + */ + public void setDaltonizerMode(int mode) { + if (mDaltonizerMode != mode) { + mDaltonizerMode = mode; + applyDaltonizerMode(mode); + } + } + + /** + * Propagates the provided color transformation matrix to the SurfaceFlinger. + */ + private static void applyColorMatrix(float[] m) { + final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); + if (flinger != null) { + final Parcel data = Parcel.obtain(); + data.writeInterfaceToken("android.ui.ISurfaceComposer"); + if (m != null) { + data.writeInt(1); + for (int i = 0; i < 16; i++) { + data.writeFloat(m[i]); + } + } else { + data.writeInt(0); + } + try { + flinger.transact(1015, data, null, 0); + } catch (RemoteException ex) { + Slog.e(TAG, "Failed to set color transform", ex); + } finally { + data.recycle(); + } + } + } + + /** + * Propagates the provided Daltonization mode to the SurfaceFlinger. + */ + private static void applyDaltonizerMode(int mode) { + final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); + if (flinger != null) { + final Parcel data = Parcel.obtain(); + data.writeInterfaceToken("android.ui.ISurfaceComposer"); + data.writeInt(mode); + try { + flinger.transact(1014, data, null, 0); + } catch (RemoteException ex) { + Slog.e(TAG, "Failed to set Daltonizer mode", ex); + } finally { + data.recycle(); + } + } + } +} diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java index 27abd1e8216d2..006747bdfca26 100644 --- a/services/core/java/com/android/server/display/NightDisplayService.java +++ b/services/core/java/com/android/server/display/NightDisplayService.java @@ -47,9 +47,14 @@ public final class NightDisplayService extends SystemService private static final boolean DEBUG = false; /** - * Night mode ~= 3400 K. + * Night display ~= 3400 K. */ - private static final String MATRIX_NIGHT = "1,0,0,0,0,.754,0,0,0,0,.516,0,0,0,0,1"; + private static final float[] MATRIX_NIGHT = new float[] { + 1, 0, 0, 0, + 0, 0.754f, 0, 0, + 0, 0, 0.516f, 0, + 0, 0, 0, 1 + }; private int mCurrentUser = UserHandle.USER_NULL; private boolean mBootCompleted; @@ -159,9 +164,9 @@ public final class NightDisplayService extends SystemService } // Update the current color matrix. - final ContentResolver cr = getContext().getContentResolver(); - Secure.putStringForUser(cr, Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, - activated ? MATRIX_NIGHT : null, mCurrentUser); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); + dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, + activated ? MATRIX_NIGHT : null); } }