Loading api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -1770,6 +1770,7 @@ package android.hardware.display { } public final class ColorDisplayManager { method public boolean setAppSaturationLevel(java.lang.String, int); method public boolean setSaturationLevel(int); } Loading core/java/android/hardware/display/ColorDisplayManager.java +26 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.hardware.display; import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; Loading Loading @@ -61,15 +63,29 @@ public final class ColorDisplayManager { * * @param saturationLevel 0-100 (inclusive), where 100 is full saturation * @return whether the saturation level change was applied successfully * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(int saturationLevel) { public boolean setSaturationLevel(@IntRange(from = 0, to = 100) int saturationLevel) { return mManager.setSaturationLevel(saturationLevel); } /** * Set the level of color saturation to apply to a specific app. * * @param packageName the package name of the app whose windows should be desaturated * @param saturationLevel 0-100 (inclusive), where 100 is full saturation * @return whether the saturation level change was applied successfully * @hide */ @SystemApi @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String packageName, @IntRange(from = 0, to = 100) int saturationLevel) { return mManager.setAppSaturationLevel(packageName, saturationLevel); } /** * Returns {@code true} if Night Display is supported by the device. * Loading Loading @@ -128,5 +144,13 @@ public final class ColorDisplayManager { throw e.rethrowFromSystemServer(); } } boolean setAppSaturationLevel(String packageName, int saturationLevel) { try { return mCdm.setAppSaturationLevel(packageName, saturationLevel); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } core/java/android/hardware/display/IColorDisplayManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -21,4 +21,5 @@ interface IColorDisplayManager { boolean isDeviceColorManaged(); boolean setSaturationLevel(int saturationLevel); boolean setAppSaturationLevel(String packageName, int saturationLevel); } No newline at end of file services/core/java/com/android/server/display/AppSaturationController.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.annotation.UserIdInt; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.ColorDisplayService.ColorTransformController; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; class AppSaturationController { private final Object mLock = new Object(); /** * A package name has one or more userIds it is running under. Each userId has zero or one * saturation level, and zero or more ColorTransformControllers. */ @GuardedBy("mLock") private final Map<String, SparseArray<SaturationController>> mAppsMap = new HashMap<>(); @VisibleForTesting static final float[] TRANSLATION_VECTOR = {0f, 0f, 0f}; /** * Add an {@link WeakReference<ColorTransformController>} for a given package and userId. */ boolean addColorTransformController(String packageName, @UserIdInt int userId, WeakReference<ColorTransformController> controller) { synchronized (mLock) { return getSaturationControllerLocked(packageName, userId) .addColorTransformController(controller); } } /** * Set the saturation level ({@code ColorDisplayManager#SaturationLevel} constant for a given * package name and userId. */ public boolean setSaturationLevel(String packageName, @UserIdInt int userId, int saturationLevel) { synchronized (mLock) { return getSaturationControllerLocked(packageName, userId) .setSaturationLevel(saturationLevel); } } /** * Dump state information. */ public void dump(PrintWriter pw) { synchronized (mLock) { pw.println("App Saturation: "); if (mAppsMap.size() == 0) { pw.println(" No packages"); return; } final List<String> packageNames = new ArrayList<>(mAppsMap.keySet()); Collections.sort(packageNames); for (String packageName : packageNames) { pw.println(" " + packageName + ":"); final SparseArray<SaturationController> appUserIdMap = mAppsMap.get(packageName); for (int i = 0; i < appUserIdMap.size(); i++) { pw.println(" " + appUserIdMap.keyAt(i) + ":"); appUserIdMap.valueAt(i).dump(pw); } } } } /** * Retrieve the SaturationController for a given package and userId, creating all intermediate * connections as needed. */ private SaturationController getSaturationControllerLocked(String packageName, @UserIdInt int userId) { return getOrCreateSaturationControllerLocked(getOrCreateUserIdMapLocked(packageName), userId); } /** * Retrieve or create the mapping between the app's given package name and its userIds (and * their SaturationControllers). */ private SparseArray<SaturationController> getOrCreateUserIdMapLocked(String packageName) { if (mAppsMap.get(packageName) != null) { return mAppsMap.get(packageName); } final SparseArray<SaturationController> appUserIdMap = new SparseArray<>(); mAppsMap.put(packageName, appUserIdMap); return appUserIdMap; } /** * Retrieve or create the mapping between an app's given userId and SaturationController. */ private SaturationController getOrCreateSaturationControllerLocked( SparseArray<SaturationController> appUserIdMap, @UserIdInt int userId) { if (appUserIdMap.get(userId) != null) { return appUserIdMap.get(userId); } final SaturationController saturationController = new SaturationController(); appUserIdMap.put(userId, saturationController); return saturationController; } @VisibleForTesting static void computeGrayscaleTransformMatrix(float saturation, float[] matrix) { float desaturation = 1.0f - saturation; float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation}; matrix[0] = luminance[0] + saturation; matrix[1] = luminance[0]; matrix[2] = luminance[0]; matrix[3] = luminance[1]; matrix[4] = luminance[1] + saturation; matrix[5] = luminance[1]; matrix[6] = luminance[2]; matrix[7] = luminance[2]; matrix[8] = luminance[2] + saturation; } private static class SaturationController { private final List<WeakReference<ColorTransformController>> mControllerRefs = new ArrayList<>(); private int mSaturationLevel = 100; private float[] mTransformMatrix = new float[9]; private boolean setSaturationLevel(int saturationLevel) { mSaturationLevel = saturationLevel; if (!mControllerRefs.isEmpty()) { return updateState(); } return false; } private boolean addColorTransformController( WeakReference<ColorTransformController> controller) { mControllerRefs.add(controller); if (mSaturationLevel != 100) { return updateState(); } else { clearExpiredReferences(); } return false; } private boolean updateState() { computeGrayscaleTransformMatrix(mSaturationLevel / 100f, mTransformMatrix); boolean updated = false; final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs .iterator(); while (iterator.hasNext()) { WeakReference<ColorTransformController> controllerRef = iterator.next(); final ColorTransformController controller = controllerRef.get(); if (controller != null) { controller.applyAppSaturation(mTransformMatrix, TRANSLATION_VECTOR); updated = true; } else { // Purge cleared refs lazily to avoid accumulating a lot of dead windows iterator.remove(); } } return updated; } private void clearExpiredReferences() { final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs .iterator(); while (iterator.hasNext()) { WeakReference<ColorTransformController> controllerRef = iterator.next(); final ColorTransformController controller = controllerRef.get(); if (controller == null) { iterator.remove(); } } } private void dump(PrintWriter pw) { pw.println(" mSaturationLevel: " + mSaturationLevel); pw.println(" mControllerRefs count: " + mControllerRefs.size()); } } } services/core/java/com/android/server/display/ColorDisplayService.java +67 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading @@ -36,8 +37,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; import android.graphics.ColorSpace; import android.hardware.display.ColorDisplayManager; import android.hardware.display.IColorDisplayManager; import android.net.Uri; import android.opengl.Matrix; Loading @@ -55,13 +56,16 @@ import android.view.animation.AnimationUtils; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ColorDisplayController; import com.android.internal.util.DumpUtils; import com.android.server.DisplayThread; import com.android.server.SystemService; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; Loading Loading @@ -400,6 +404,8 @@ public final class ColorDisplayService extends SystemService { private final Handler mHandler; private final AppSaturationController mAppSaturationController = new AppSaturationController(); private int mCurrentUser = UserHandle.USER_NULL; private ContentObserver mUserSetupObserver; private boolean mBootCompleted; Loading Loading @@ -829,6 +835,22 @@ public final class ColorDisplayService extends SystemService { return LocalDateTime.MIN; } private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) { return mAppSaturationController .setSaturationLevel(packageName, mCurrentUser, saturationLevel); } private void dumpInternal(PrintWriter pw) { pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)"); pw.println("Night Display:"); if (ColorDisplayManager.isNightDisplayAvailable(getContext())) { pw.println(" Activated: " + mNightDisplayTintController.isActivated()); } else { pw.println(" Not available"); } mAppSaturationController.dump(pw); } private abstract class NightDisplayAutoMode { public abstract void onActivated(boolean activated); Loading Loading @@ -1132,6 +1154,16 @@ public final class ColorDisplayService extends SystemService { public void dump(PrintWriter pw) { mDisplayWhiteBalanceTintController.dump(pw); } /** * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed. */ public boolean attachColorTransformController(String packageName, int uid, WeakReference<ColorTransformController> controller) { return mAppSaturationController .addColorTransformController(packageName, uid, controller); } } /** Loading Loading @@ -1163,6 +1195,15 @@ public final class ColorDisplayService extends SystemService { } } /** * Interface for applying transforms to a given AppWindow. */ public interface ColorTransformController { /** Apply the given saturation (grayscale) matrix to the associated AppWindow. */ void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation); } private final class BinderService extends IColorDisplayManager.Stub { @Override Loading Loading @@ -1196,5 +1237,30 @@ public final class ColorDisplayService extends SystemService { } return true; } @Override public boolean setAppSaturationLevel(String packageName, int level) { getContext().enforceCallingPermission( Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, "Permission required to set display saturation level"); final long token = Binder.clearCallingIdentity(); try { return setAppSaturationLevelInternal(packageName, level); } finally { Binder.restoreCallingIdentity(token); } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; final long token = Binder.clearCallingIdentity(); try { dumpInternal(pw); } finally { Binder.restoreCallingIdentity(token); } } } } Loading
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -1770,6 +1770,7 @@ package android.hardware.display { } public final class ColorDisplayManager { method public boolean setAppSaturationLevel(java.lang.String, int); method public boolean setSaturationLevel(int); } Loading
core/java/android/hardware/display/ColorDisplayManager.java +26 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.hardware.display; import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; Loading Loading @@ -61,15 +63,29 @@ public final class ColorDisplayManager { * * @param saturationLevel 0-100 (inclusive), where 100 is full saturation * @return whether the saturation level change was applied successfully * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(int saturationLevel) { public boolean setSaturationLevel(@IntRange(from = 0, to = 100) int saturationLevel) { return mManager.setSaturationLevel(saturationLevel); } /** * Set the level of color saturation to apply to a specific app. * * @param packageName the package name of the app whose windows should be desaturated * @param saturationLevel 0-100 (inclusive), where 100 is full saturation * @return whether the saturation level change was applied successfully * @hide */ @SystemApi @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String packageName, @IntRange(from = 0, to = 100) int saturationLevel) { return mManager.setAppSaturationLevel(packageName, saturationLevel); } /** * Returns {@code true} if Night Display is supported by the device. * Loading Loading @@ -128,5 +144,13 @@ public final class ColorDisplayManager { throw e.rethrowFromSystemServer(); } } boolean setAppSaturationLevel(String packageName, int saturationLevel) { try { return mCdm.setAppSaturationLevel(packageName, saturationLevel); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } }
core/java/android/hardware/display/IColorDisplayManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -21,4 +21,5 @@ interface IColorDisplayManager { boolean isDeviceColorManaged(); boolean setSaturationLevel(int saturationLevel); boolean setAppSaturationLevel(String packageName, int saturationLevel); } No newline at end of file
services/core/java/com/android/server/display/AppSaturationController.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.annotation.UserIdInt; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.ColorDisplayService.ColorTransformController; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; class AppSaturationController { private final Object mLock = new Object(); /** * A package name has one or more userIds it is running under. Each userId has zero or one * saturation level, and zero or more ColorTransformControllers. */ @GuardedBy("mLock") private final Map<String, SparseArray<SaturationController>> mAppsMap = new HashMap<>(); @VisibleForTesting static final float[] TRANSLATION_VECTOR = {0f, 0f, 0f}; /** * Add an {@link WeakReference<ColorTransformController>} for a given package and userId. */ boolean addColorTransformController(String packageName, @UserIdInt int userId, WeakReference<ColorTransformController> controller) { synchronized (mLock) { return getSaturationControllerLocked(packageName, userId) .addColorTransformController(controller); } } /** * Set the saturation level ({@code ColorDisplayManager#SaturationLevel} constant for a given * package name and userId. */ public boolean setSaturationLevel(String packageName, @UserIdInt int userId, int saturationLevel) { synchronized (mLock) { return getSaturationControllerLocked(packageName, userId) .setSaturationLevel(saturationLevel); } } /** * Dump state information. */ public void dump(PrintWriter pw) { synchronized (mLock) { pw.println("App Saturation: "); if (mAppsMap.size() == 0) { pw.println(" No packages"); return; } final List<String> packageNames = new ArrayList<>(mAppsMap.keySet()); Collections.sort(packageNames); for (String packageName : packageNames) { pw.println(" " + packageName + ":"); final SparseArray<SaturationController> appUserIdMap = mAppsMap.get(packageName); for (int i = 0; i < appUserIdMap.size(); i++) { pw.println(" " + appUserIdMap.keyAt(i) + ":"); appUserIdMap.valueAt(i).dump(pw); } } } } /** * Retrieve the SaturationController for a given package and userId, creating all intermediate * connections as needed. */ private SaturationController getSaturationControllerLocked(String packageName, @UserIdInt int userId) { return getOrCreateSaturationControllerLocked(getOrCreateUserIdMapLocked(packageName), userId); } /** * Retrieve or create the mapping between the app's given package name and its userIds (and * their SaturationControllers). */ private SparseArray<SaturationController> getOrCreateUserIdMapLocked(String packageName) { if (mAppsMap.get(packageName) != null) { return mAppsMap.get(packageName); } final SparseArray<SaturationController> appUserIdMap = new SparseArray<>(); mAppsMap.put(packageName, appUserIdMap); return appUserIdMap; } /** * Retrieve or create the mapping between an app's given userId and SaturationController. */ private SaturationController getOrCreateSaturationControllerLocked( SparseArray<SaturationController> appUserIdMap, @UserIdInt int userId) { if (appUserIdMap.get(userId) != null) { return appUserIdMap.get(userId); } final SaturationController saturationController = new SaturationController(); appUserIdMap.put(userId, saturationController); return saturationController; } @VisibleForTesting static void computeGrayscaleTransformMatrix(float saturation, float[] matrix) { float desaturation = 1.0f - saturation; float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation}; matrix[0] = luminance[0] + saturation; matrix[1] = luminance[0]; matrix[2] = luminance[0]; matrix[3] = luminance[1]; matrix[4] = luminance[1] + saturation; matrix[5] = luminance[1]; matrix[6] = luminance[2]; matrix[7] = luminance[2]; matrix[8] = luminance[2] + saturation; } private static class SaturationController { private final List<WeakReference<ColorTransformController>> mControllerRefs = new ArrayList<>(); private int mSaturationLevel = 100; private float[] mTransformMatrix = new float[9]; private boolean setSaturationLevel(int saturationLevel) { mSaturationLevel = saturationLevel; if (!mControllerRefs.isEmpty()) { return updateState(); } return false; } private boolean addColorTransformController( WeakReference<ColorTransformController> controller) { mControllerRefs.add(controller); if (mSaturationLevel != 100) { return updateState(); } else { clearExpiredReferences(); } return false; } private boolean updateState() { computeGrayscaleTransformMatrix(mSaturationLevel / 100f, mTransformMatrix); boolean updated = false; final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs .iterator(); while (iterator.hasNext()) { WeakReference<ColorTransformController> controllerRef = iterator.next(); final ColorTransformController controller = controllerRef.get(); if (controller != null) { controller.applyAppSaturation(mTransformMatrix, TRANSLATION_VECTOR); updated = true; } else { // Purge cleared refs lazily to avoid accumulating a lot of dead windows iterator.remove(); } } return updated; } private void clearExpiredReferences() { final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs .iterator(); while (iterator.hasNext()) { WeakReference<ColorTransformController> controllerRef = iterator.next(); final ColorTransformController controller = controllerRef.get(); if (controller == null) { iterator.remove(); } } } private void dump(PrintWriter pw) { pw.println(" mSaturationLevel: " + mSaturationLevel); pw.println(" mControllerRefs count: " + mControllerRefs.size()); } } }
services/core/java/com/android/server/display/ColorDisplayService.java +67 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading @@ -36,8 +37,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; import android.graphics.ColorSpace; import android.hardware.display.ColorDisplayManager; import android.hardware.display.IColorDisplayManager; import android.net.Uri; import android.opengl.Matrix; Loading @@ -55,13 +56,16 @@ import android.view.animation.AnimationUtils; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ColorDisplayController; import com.android.internal.util.DumpUtils; import com.android.server.DisplayThread; import com.android.server.SystemService; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; Loading Loading @@ -400,6 +404,8 @@ public final class ColorDisplayService extends SystemService { private final Handler mHandler; private final AppSaturationController mAppSaturationController = new AppSaturationController(); private int mCurrentUser = UserHandle.USER_NULL; private ContentObserver mUserSetupObserver; private boolean mBootCompleted; Loading Loading @@ -829,6 +835,22 @@ public final class ColorDisplayService extends SystemService { return LocalDateTime.MIN; } private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) { return mAppSaturationController .setSaturationLevel(packageName, mCurrentUser, saturationLevel); } private void dumpInternal(PrintWriter pw) { pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)"); pw.println("Night Display:"); if (ColorDisplayManager.isNightDisplayAvailable(getContext())) { pw.println(" Activated: " + mNightDisplayTintController.isActivated()); } else { pw.println(" Not available"); } mAppSaturationController.dump(pw); } private abstract class NightDisplayAutoMode { public abstract void onActivated(boolean activated); Loading Loading @@ -1132,6 +1154,16 @@ public final class ColorDisplayService extends SystemService { public void dump(PrintWriter pw) { mDisplayWhiteBalanceTintController.dump(pw); } /** * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed. */ public boolean attachColorTransformController(String packageName, int uid, WeakReference<ColorTransformController> controller) { return mAppSaturationController .addColorTransformController(packageName, uid, controller); } } /** Loading Loading @@ -1163,6 +1195,15 @@ public final class ColorDisplayService extends SystemService { } } /** * Interface for applying transforms to a given AppWindow. */ public interface ColorTransformController { /** Apply the given saturation (grayscale) matrix to the associated AppWindow. */ void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation); } private final class BinderService extends IColorDisplayManager.Stub { @Override Loading Loading @@ -1196,5 +1237,30 @@ public final class ColorDisplayService extends SystemService { } return true; } @Override public boolean setAppSaturationLevel(String packageName, int level) { getContext().enforceCallingPermission( Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, "Permission required to set display saturation level"); final long token = Binder.clearCallingIdentity(); try { return setAppSaturationLevelInternal(packageName, level); } finally { Binder.restoreCallingIdentity(token); } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; final long token = Binder.clearCallingIdentity(); try { dumpInternal(pw); } finally { Binder.restoreCallingIdentity(token); } } } }