1 /* 2 * Copyright (C) 2021 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.compatibility.common.util; 18 19 import android.content.Context; 20 import android.hardware.display.DisplayManager; 21 import android.hardware.hdmi.HdmiControlManager; 22 import android.view.Display; 23 24 import java.util.concurrent.CountDownLatch; 25 import java.util.concurrent.TimeUnit; 26 27 public class DisplayUtil { 28 29 private static final float REFRESH_RATE_TOLERANCE = 0.01f; 30 31 /** 32 * Returns if a physical display is connected to DUT. The method may return a false positive, 33 * but no false negative. 34 */ isDisplayConnected(Context context)35 public static boolean isDisplayConnected(Context context) throws Exception { 36 // DisplayManager will return a display even if there is no connected display. 37 // For that reason we use HdmiControlManager to check if there's something connected 38 // to the HDMI port. 39 HdmiControlManager cecManager = context.getSystemService(HdmiControlManager.class); 40 41 if (cecManager == null) { 42 // CEC is not available. Can't do anything more, so assume that there is a display. 43 return true; 44 } 45 46 if (cecManager.getPlaybackClient() == null) { 47 // The device is not HDMI playback device (e.g. set-top box), so we assume it has 48 // a built-in display. 49 return true; 50 } 51 52 CountDownLatch notifyLatch = new CountDownLatch(1); 53 cecManager.addHotplugEventListener(event -> { 54 // TODO(b/189837682): Check if the port is HDMI out 55 if (event.isConnected()) { 56 notifyLatch.countDown(); 57 } 58 }); 59 60 return notifyLatch.await(3, TimeUnit.SECONDS); 61 } 62 isModeSwitchSeamless(Display.Mode from, Display.Mode to)63 public static boolean isModeSwitchSeamless(Display.Mode from, Display.Mode to) { 64 if (from.getModeId() == to.getModeId()) { 65 return true; 66 } 67 68 if (from.getPhysicalHeight() != to.getPhysicalHeight() 69 || from.getPhysicalWidth() != to.getPhysicalWidth()) { 70 return false; 71 } 72 73 for (float alternativeRefreshRate : from.getAlternativeRefreshRates()) { 74 if (Math.abs(alternativeRefreshRate - to.getRefreshRate()) < REFRESH_RATE_TOLERANCE) { 75 return true; 76 } 77 } 78 79 return false; 80 } 81 getRefreshRateSwitchingType(DisplayManager displayManager)82 public static int getRefreshRateSwitchingType(DisplayManager displayManager) { 83 return toSwitchingType(displayManager.getMatchContentFrameRateUserPreference()); 84 } 85 toSwitchingType(int matchContentFrameRateUserPreference)86 private static int toSwitchingType(int matchContentFrameRateUserPreference) { 87 switch (matchContentFrameRateUserPreference) { 88 case DisplayManager.MATCH_CONTENT_FRAMERATE_NEVER: 89 return DisplayManager.SWITCHING_TYPE_NONE; 90 case DisplayManager.MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY: 91 return DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; 92 case DisplayManager.MATCH_CONTENT_FRAMERATE_ALWAYS: 93 return DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; 94 default: 95 return -1; 96 } 97 } 98 } 99