overview
平台: RK3568 + Android 11
On some special days, such as days of silence, disaster days, anniversaries, mourning days, etc., many apps, web pages, posters, etc. have begun to use black and white themes. For Android's global black and white implementation, you can consider using the method of simulating the color space .
With the hardware-accelerated rendering option, you can take advantage of hardware-based options such as GPU, hardware layers, and multi-sample anti-aliasing (MSAA) to optimize your application for the target hardware platform.
Tap Simulate Color Space to change the color scheme of the entire device interface. The options below this setting refer to the type of color blindness. The options are as follows:
- Disabled (no simulated color scheme)
- Achromatopsia (color scheme limited to black, white, and gray)
- Deuteranomaly (affects the display of red and green)
- Protomaly (affects the display of red and green)
- Procyanomaly (affects the display of blue and yellow)
Among them, "promatomaly" refers to red-green color blindness, protanomaly; "deuteranomaly" (shown in Figure 8) refers to red-green color blindness, deuteranomaly.
If you take screenshots in the simulated color space, they will display normally as if the color scheme had not been changed.
accomplish
It can be found in the development options of Settings: Settings > System > Developer Options > Simulation Color Space ,
text source
rk3568_a11$ grep -r "模拟颜色空间" frameworks/base/packages/SettingsLib/
frameworks/base/packages/SettingsLib/res/values-zh-rCN/strings.xml
<string name="simulate_color_space" msgid="1206503300335835151">"模拟颜色空间"</string>
<string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"全色盲"</string>
<string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"绿色弱视(红绿不分)"</string>
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string>
rk3568_a11$ grep -r "simulate_color_space" packages/apps/Settings
packages/apps/Settings/tests/robotests/src/com/android/settings/development/SimulateColorSpacePreferenceControllerTest.java: mListValues = mContext.getResources().getStringArray(R.array.simulate_color_space_values);
packages/apps/Settings/src/com/android/settings/development/SimulateColorSpacePreferenceController.java: private static final String SIMULATE_COLOR_SPACE = "simulate_color_space";
packages/apps/Settings/res/xml/development_settings.xml: android:entries="@array/simulate_color_space_entries"
packages/apps/Settings/res/xml/development_settings.xml: android:entryValues="@array/simulate_color_space_values"
packages/apps/Settings/res/xml/development_settings.xml: android:key="simulate_color_space"
packages/apps/Settings/res/xml/development_settings.xml: android:title="@string/simulate_color_space" />
packages/apps/Settings/res/xml/development_settings.xml Developer Options
<ListPreference
android:entries="@array/simulate_color_space_entries"
android:entryValues="@array/simulate_color_space_values"
android:key="simulate_color_space"
android:summary="%s"
android:title="@string/simulate_color_space" />
The value of the corresponding mode
frameworks/base/packages/SettingsLib/res/values/arrays.xml
<!-- Display color space adjustment modes for developers -->
<string-array name="simulate_color_space_entries" translatable="false">
<item>@string/daltonizer_mode_disabled</item>
<item>@string/daltonizer_mode_monochromacy</item>
<item>@string/daltonizer_mode_deuteranomaly</item>
<item>@string/daltonizer_mode_protanomaly</item>
<item>@string/daltonizer_mode_tritanomaly</item>
</string-array>
<!-- Values for display color space adjustment modes for developers -->
<string-array name="simulate_color_space_values" translatable="false">
<item>-1</item>
<item>0</item>
<item>2</item>
<item>1</item>
<item>3</item>
</string-array>
Modify system settings, mainly enable and mode
packages/apps/Settings/src/com/android/settings/development/SimulateColorSpacePreferenceController.java
private void writeSimulateColorSpace(Object value) {
final ContentResolver cr = mContext.getContentResolver();
final int newMode = Integer.parseInt(value.toString());
if (newMode < 0) {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
SETTING_VALUE_OFF);
} else {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
SETTING_VALUE_ON);
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, newMode);
}
}
Monitor changes in setting items in the service and execute responses
frameworks/base/services/core/java/com/android/server/display/color/ColorDisplayService.java
/**
* Apply the accessibility daltonizer transform based on the settings value.
*/
private void onAccessibilityDaltonizerChanged() {
if (mCurrentUser == UserHandle.USER_NULL) {
return;
}
final int daltonizerMode = isAccessiblityDaltonizerEnabled()
? Secure.getIntForUser(getContext().getContentResolver(),
Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
: AccessibilityManager.DALTONIZER_DISABLED;
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
// Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
MATRIX_GRAYSCALE);
dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
} else {
dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
dtm.setDaltonizerMode(daltonizerMode);
}
}
frameworks/base/services/core/java/com/android/server/display/color/DisplayTransformManager.java
private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014
/**
* Sets and applies a current color transform matrix for a given level.
* <p>
* Note: all color transforms are first composed to a single matrix in ascending order based on
* level before being applied to the display.
*
* @param level 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 level, float[] value) {
if (value != null && value.length != 16) {
throw new IllegalArgumentException("Expected length: 16 (4x4 matrix)"
+ ", actual length: " + value.length);
}
synchronized (mColorMatrix) {
final float[] oldValue = mColorMatrix.get(level);
if (!Arrays.equals(oldValue, value)) {
if (value == null) {
mColorMatrix.remove(level);
} else if (oldValue == null) {
mColorMatrix.put(level, Arrays.copyOf(value, value.length));
} else {
System.arraycopy(value, 0, oldValue, 0, value.length);
}
// Update the current color transform.
applyColorMatrix(computeColorMatrixLocked());
}
}
}
/**
* 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) {
synchronized (mDaltonizerModeLock) {
if (mDaltonizerMode != mode) {
mDaltonizerMode = mode;
applyDaltonizerMode(mode);
}
}
}
/**
* Propagates the provided Daltonization mode to the SurfaceFlinger.
*/
private static void applyDaltonizerMode(int mode) {
final Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
data.writeInt(mode);
try {
sFlinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to set Daltonizer mode", ex);
} finally {
data.recycle();
}
}
Pass to SurfaceFlinger
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
//............
switch (code) {
case 1014: {
Mutex::Autolock _l(mStateLock);
// daltonize
n = data.readInt32();
switch (n % 10) {
case 1:
mDaltonizer.setType(ColorBlindnessType::Protanomaly);
break;
case 2:
mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
break;
case 3:
mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
break;
default:
mDaltonizer.setType(ColorBlindnessType::None);
break;
}
if (n >= 10) {
mDaltonizer.setMode(ColorBlindnessMode::Correction);
} else {
mDaltonizer.setMode(ColorBlindnessMode::Simulation);
}
updateColorMatrixLocked();
return NO_ERROR;
}
//........................
About Settings > Color Correction
The principle of implementation is the same as black and white:
packages/apps/Settings/res/xml/accessibility_daltonizer_settings.xml
<PreferenceCategory
android:title="@string/daltonizer_type"
android:key="daltonizer_mode_category" >
<com.android.settingslib.widget.RadioButtonPreference
android:key="daltonizer_mode_deuteranomaly"
android:persistent="false"
android:summary="@string/daltonizer_mode_deuteranomaly_summary"
android:title="@string/daltonizer_mode_deuteranomaly_title" />
<com.android.settingslib.widget.RadioButtonPreference
android:key="daltonizer_mode_protanomaly"
android:persistent="false"
android:summary="@string/daltonizer_mode_protanomaly_summary"
android:title="@string/daltonizer_mode_protanomaly_title" />
<com.android.settingslib.widget.RadioButtonPreference
android:key="daltonizer_mode_tritanomaly"
android:persistent="false"
android:summary="@string/daltonizer_mode_tritanomaly_summary"
android:title="@string/daltonizer_mode_tritanomaly_title" />
</PreferenceCategory>
packages/apps/Settings/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_daltonizer_settings;
}
packages/apps/Settings/src/com/android/settings/accessibility/DaltonizerRadioButtonPreferenceController.java
private static final String TYPE = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER;
private void putSecureString(String name, String value) {
Settings.Secure.putString(mContentResolver, name, value);
}
private void handlePreferenceChange(String value) {
putSecureString(TYPE, value);
}
How to call the APP?
Ordinary APP does not have the permission to call, there are two calling methods:
- App has system uid
final android.content.ContentResolver cr = context.getContentResolver();
final int newMode = on ? 0 : -1;
if (newMode < 0) {
android.provider.Settings.Secure.putInt(cr, "accessibility_display_daltonizer_enabled",
0);
} else {
android.provider.Settings.Secure.putInt(cr, "accessibility_display_daltonizer_enabled",
1);
//public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
// "accessibility_display_daltonizer";
android.provider.Settings.Secure.putInt(cr, "accessibility_display_daltonizer", newMode);
}
- The platform is ROOT, execute the command
settings put secure accessibility_display_daltonizer_enabled 1
settings put secure accessibility_display_daltonizer 0
reference
Android APP global black and white implementation scheme
Android global setting APP to black and white mode two solutions
Configure the developer options on the device