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