diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 95a98f1e94943..fa4ba38e45c03 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -58,6 +58,7 @@ import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings.Secure; @@ -819,7 +820,13 @@ public final class ColorDisplayService extends SystemService { return LocalDateTime.MIN; } - private boolean setAppSaturationLevelInternal(String callingPackageName, + void setSaturationLevelInternal(int saturationLevel) { + final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION); + message.arg1 = saturationLevel; + mHandler.sendMessage(message); + } + + boolean setAppSaturationLevelInternal(String callingPackageName, String affectedPackageName, int saturationLevel) { return mAppSaturationController .setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser, @@ -1509,9 +1516,7 @@ public final class ColorDisplayService extends SystemService { } final long token = Binder.clearCallingIdentity(); try { - final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION); - message.arg1 = level; - mHandler.sendMessage(message); + setSaturationLevelInternal(level); } finally { Binder.restoreCallingIdentity(token); } @@ -1724,5 +1729,22 @@ public final class ColorDisplayService extends SystemService { Binder.restoreCallingIdentity(token); } } + + @Override + public int handleShellCommand(ParcelFileDescriptor in, + ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args) { + getContext().enforceCallingOrSelfPermission( + Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, + "Permission required to use ADB color transform commands"); + final long token = Binder.clearCallingIdentity(); + try { + return new ColorDisplayShellCommand(ColorDisplayService.this) + .exec(this, in.getFileDescriptor(), out.getFileDescriptor(), + err.getFileDescriptor(), + args); + } finally { + Binder.restoreCallingIdentity(token); + } + } } } diff --git a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java new file mode 100644 index 0000000000000..b4555f851d4d5 --- /dev/null +++ b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 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.color; + +import android.content.pm.PackageManagerInternal; +import android.os.ShellCommand; + +import com.android.server.LocalServices; + +class ColorDisplayShellCommand extends ShellCommand { + + private static final String USAGE = "usage: cmd color_display SUBCOMMAND [ARGS]\n" + + " help\n" + + " Shows this message.\n" + + " set-saturation LEVEL\n" + + " Sets the device saturation to the given LEVEL, 0-100 inclusive.\n" + + " set-layer-saturation CALLER_PACKAGE TARGET_PACKAGE LEVEL\n" + + " Sets the saturation LEVEL for all layers of the TARGET_PACKAGE, attributed\n" + + " to the CALLER_PACKAGE. The lowest LEVEL from any CALLER_PACKAGE is applied.\n"; + + private static final int ERROR = -1; + private static final int SUCCESS = 0; + + private final ColorDisplayService mService; + + ColorDisplayShellCommand(ColorDisplayService service) { + mService = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + switch (cmd) { + case "set-saturation": + return setSaturation(); + case "set-layer-saturation": + return setLayerSaturation(); + default: + return handleDefaultCommands(cmd); + } + } + + private int setSaturation() { + final int level = getLevel(); + if (level == ERROR) { + return ERROR; + } + mService.setSaturationLevelInternal(level); + return SUCCESS; + } + + private int setLayerSaturation() { + final int level = getLevel(); + if (level == ERROR) { + return ERROR; + } + final String callerPackageName = getPackageName(); + if (callerPackageName == null) { + getErrPrintWriter().println("Error: CALLER_PACKAGE must be an installed package name"); + return ERROR; + } + final String targetPackageName = getPackageName(); + if (targetPackageName == null) { + getErrPrintWriter().println("Error: TARGET_PACKAGE must be an installed package name"); + return ERROR; + } + mService.setAppSaturationLevelInternal(callerPackageName, targetPackageName, level); + return SUCCESS; + } + + private String getPackageName() { + final String packageNameArg = getNextArg(); + return LocalServices.getService(PackageManagerInternal.class).getPackage(packageNameArg) + == null + ? null : packageNameArg; + } + + private int getLevel() { + final String levelArg = getNextArg(); + if (levelArg == null) { + getErrPrintWriter().println("Error: Required argument LEVEL is unspecified"); + return ERROR; + } + final int level; + try { + level = Integer.parseInt(levelArg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: LEVEL argument is not an integer"); + return ERROR; + } + if (level < 0 || level > 100) { + getErrPrintWriter() + .println("Error: LEVEL argument must be an integer between 0 and 100"); + return ERROR; + } + return level; + } + + @Override + public void onHelp() { + getOutPrintWriter().print(USAGE); + } +}