1 /* 2 * Copyright (C) 2023 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 17 package com.android.tv.settings.device.displaysound; 18 19 import static android.view.Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION; 20 21 import android.annotation.Nullable; 22 import android.app.AlertDialog; 23 import android.content.Context; 24 import android.content.DialogInterface.OnClickListener; 25 import android.content.Intent; 26 import android.hardware.display.DisplayManager; 27 import android.hardware.display.HdrConversionMode; 28 import android.os.UserHandle; 29 import android.view.Display; 30 31 import com.android.tv.settings.R; 32 33 import java.util.Arrays; 34 import java.util.Set; 35 import java.util.stream.Collectors; 36 37 /** 38 * Helper methods for display and sound settings. 39 * 40 * @hide 41 */ 42 public class DisplaySoundUtils { 43 private static final String ACTION_HDR_SETTINGS_CHANGED = 44 "com.android.tv.settings.display.HDR_SETTINGS_CHANGED"; 45 sendHdrSettingsChangedBroadcast(Context context)46 public static void sendHdrSettingsChangedBroadcast(Context context) { 47 final String target_package = 48 context.getResources().getString(R.string.hdr_settings_changed_broadcast_package); 49 if (target_package.isEmpty()) { 50 return; 51 } 52 context.sendBroadcastAsUser( 53 new Intent(ACTION_HDR_SETTINGS_CHANGED) 54 .setPackage(target_package) 55 .setFlags( 56 Intent.FLAG_INCLUDE_STOPPED_PACKAGES 57 | Intent.FLAG_RECEIVER_FOREGROUND 58 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND), 59 UserHandle.SYSTEM); 60 } 61 62 /** Gets the match-content dynamic range status */ getMatchContentDynamicRangeStatus(DisplayManager displayManager)63 public static boolean getMatchContentDynamicRangeStatus(DisplayManager displayManager) { 64 return displayManager.getHdrConversionModeSetting().getConversionMode() 65 == HdrConversionMode.HDR_CONVERSION_PASSTHROUGH; 66 } 67 68 /** Sets the match-content dynamic range status */ setMatchContentDynamicRangeStatus(Context context, DisplayManager displayManager, boolean status)69 public static void setMatchContentDynamicRangeStatus(Context context, 70 DisplayManager displayManager, 71 boolean status) { 72 HdrConversionMode mode = status 73 ? new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH) 74 : new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM); 75 76 displayManager.setHdrConversionMode(mode); 77 sendHdrSettingsChangedBroadcast(context); 78 } 79 80 /** Returns if Dolby vision is supported by the device */ isDolbyVisionSupported(Display.Mode[] modes)81 public static boolean isDolbyVisionSupported(Display.Mode[] modes) { 82 for (int i = 0; i < modes.length; i++) { 83 if (isHdrFormatSupported(modes[i], HDR_TYPE_DOLBY_VISION)) { 84 return true; 85 } 86 } 87 return false; 88 } 89 90 /** Returns if the passed HDR format is supported by the device in case of a specific mode */ isHdrFormatSupported(Display.Mode mode, int hdrFormat)91 public static boolean isHdrFormatSupported(Display.Mode mode, int hdrFormat) { 92 return Arrays.stream(mode.getSupportedHdrTypes()).anyMatch( 93 hdr -> hdr == hdrFormat); 94 } 95 96 /** 97 * Returns true if the current mode is above 4k30Hz and this is a device that does not support 98 * Dolby Vision at resolutions above 4k30Hz 99 */ doesCurrentModeNotSupportDvBecauseLimitedTo4k30(Display display)100 public static boolean doesCurrentModeNotSupportDvBecauseLimitedTo4k30(Display display) { 101 Display.Mode[] supportedModes = display.getSupportedModes(); 102 Display.Mode currentMode = display.getMode(); 103 boolean is4k60HzMode = (currentMode.getPhysicalHeight() >= 2160 104 || currentMode.getPhysicalWidth() >= 2160) 105 && currentMode.getRefreshRate() >= 59.9; 106 107 return is4k60HzMode && isDolbyVisionSupported(supportedModes) 108 && !isHdrFormatSupported(currentMode, HDR_TYPE_DOLBY_VISION); 109 } 110 111 /** 112 * Returns a 1080p 60Hz mode if one is supported by the display, null otherwise 113 */ 114 @Nullable findMode1080p60(Display display)115 public static Display.Mode findMode1080p60(Display display) { 116 for (Display.Mode mode : display.getSupportedModes()) { 117 if (mode.getPhysicalWidth() == 1920 && mode.getPhysicalHeight() == 1080 118 && mode.getRefreshRate() >= 59.9) { 119 return mode; 120 } 121 } 122 return null; 123 } 124 createAlertDialog(Context context, String title, String description, OnClickListener onOkClicked, OnClickListener onCancelClicked)125 static AlertDialog createAlertDialog(Context context, String title, String description, 126 OnClickListener onOkClicked, OnClickListener onCancelClicked) { 127 return new AlertDialog.Builder(context) 128 .setTitle(title) 129 .setMessage(description) 130 .setPositiveButton(R.string.resolution_selection_dialog_ok, onOkClicked) 131 .setNegativeButton(R.string.resolution_selection_dialog_cancel, onCancelClicked) 132 .create(); 133 } 134 enableHdrType(DisplayManager displayManager, int hdrType)135 static void enableHdrType(DisplayManager displayManager, int hdrType) { 136 Set<Integer> disabledHdrTypes = toSet(displayManager.getUserDisabledHdrTypes()); 137 disabledHdrTypes.remove(hdrType); 138 displayManager.setUserDisabledHdrTypes(toArray(disabledHdrTypes)); 139 } 140 disableHdrType(DisplayManager displayManager, int hdrType)141 static void disableHdrType(DisplayManager displayManager, int hdrType) { 142 Set<Integer> disabledHdrTypes = toSet(displayManager.getUserDisabledHdrTypes()); 143 disabledHdrTypes.add(hdrType); 144 displayManager.setUserDisabledHdrTypes(toArray(disabledHdrTypes)); 145 } 146 147 /** Converts set to int array */ toArray(Set<Integer> set)148 public static int[] toArray(Set<Integer> set) { 149 return set.stream().mapToInt(Integer::intValue).toArray(); 150 } 151 152 /** Converts int array to set */ toSet(int[] array)153 public static Set<Integer> toSet(int[] array) { 154 return Arrays.stream(array).boxed().collect(Collectors.toSet()); 155 } 156 } 157