1 /* 2 * Copyright (C) 2022 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.internal.jank; 18 19 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD; 20 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD; 21 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD; 22 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD; 23 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION; 24 25 import android.annotation.IntDef; 26 import android.annotation.Nullable; 27 import android.hardware.display.DisplayManager; 28 import android.hardware.display.DisplayManagerGlobal; 29 import android.os.Handler; 30 import android.util.SparseArray; 31 import android.view.DisplayInfo; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 38 /** 39 * A class that tracks the display resolutions. 40 * @hide 41 */ 42 public class DisplayResolutionTracker { 43 private static final String TAG = DisplayResolutionTracker.class.getSimpleName(); 44 45 public static final int RESOLUTION_UNKNOWN = 46 UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION; 47 public static final int RESOLUTION_SD = 48 UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD; 49 public static final int RESOLUTION_HD = 50 UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD; 51 public static final int RESOLUTION_FHD = 52 UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD; 53 public static final int RESOLUTION_QHD = 54 UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD; 55 56 /** @hide */ 57 @IntDef({ 58 RESOLUTION_UNKNOWN, 59 RESOLUTION_SD, 60 RESOLUTION_HD, 61 RESOLUTION_FHD, 62 RESOLUTION_QHD, 63 }) 64 @Retention(RetentionPolicy.SOURCE) 65 public @interface Resolution { 66 } 67 68 private final DisplayInterface mManager; 69 private final SparseArray<Integer> mResolutions = new SparseArray<>(); 70 private final Object mLock = new Object(); 71 DisplayResolutionTracker(@ullable Handler handler)72 public DisplayResolutionTracker(@Nullable Handler handler) { 73 this(DisplayInterface.getDefault(handler)); 74 } 75 76 @VisibleForTesting DisplayResolutionTracker(DisplayInterface manager)77 public DisplayResolutionTracker(DisplayInterface manager) { 78 mManager = manager; 79 mManager.registerDisplayListener(new DisplayManager.DisplayListener() { 80 @Override 81 public void onDisplayAdded(int displayId) { 82 updateDisplay(displayId); 83 } 84 85 @Override 86 public void onDisplayChanged(int displayId) { 87 updateDisplay(displayId); 88 } 89 90 @Override 91 public void onDisplayRemoved(int displayId) { 92 // Not in the event mask below, won't be called. 93 } 94 }); 95 } 96 updateDisplay(int displayId)97 private void updateDisplay(int displayId) { 98 DisplayInfo info = mManager.getDisplayInfo(displayId); 99 if (info == null) { 100 return; 101 } 102 @Resolution int resolution = getResolution(info); 103 104 synchronized (mLock) { 105 mResolutions.put(displayId, resolution); 106 } 107 } 108 109 /** 110 * Returns the (cached) resolution of the display with the given ID. 111 */ 112 @Resolution getResolution(int displayId)113 public int getResolution(int displayId) { 114 return mResolutions.get(displayId, RESOLUTION_UNKNOWN); 115 } 116 117 /** 118 * Returns the resolution of the given {@link DisplayInfo}. 119 */ 120 @VisibleForTesting 121 @Resolution getResolution(DisplayInfo info)122 public static int getResolution(DisplayInfo info) { 123 int smaller = Math.min(info.logicalWidth, info.logicalHeight); 124 int larger = Math.max(info.logicalWidth, info.logicalHeight); 125 if (smaller < 720 || larger < 1280) { 126 return RESOLUTION_SD; 127 } else if (smaller < 1080 || larger < 1920) { 128 return RESOLUTION_HD; 129 } else if (smaller < 1440 || larger < 2560) { 130 return RESOLUTION_FHD; 131 } else { 132 return RESOLUTION_QHD; 133 } 134 } 135 136 /** 137 * Wrapper around the final {@link DisplayManagerGlobal} class. 138 * @hide 139 */ 140 @VisibleForTesting 141 public interface DisplayInterface { 142 /** Reurns an implementation wrapping {@link DisplayManagerGlobal}. */ getDefault(@ullable Handler handler)143 static DisplayInterface getDefault(@Nullable Handler handler) { 144 DisplayManagerGlobal manager = DisplayManagerGlobal.getInstance(); 145 return new DisplayInterface() { 146 @Override 147 public void registerDisplayListener(DisplayManager.DisplayListener listener) { 148 manager.registerDisplayListener(listener, handler, 149 DisplayManager.EVENT_FLAG_DISPLAY_ADDED 150 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED); 151 } 152 153 @Override 154 public DisplayInfo getDisplayInfo(int displayId) { 155 return manager.getDisplayInfo(displayId); 156 } 157 }; 158 } 159 160 /** {@see DisplayManagerGlobal#registerDisplayListener} */ registerDisplayListener(DisplayManager.DisplayListener listener)161 void registerDisplayListener(DisplayManager.DisplayListener listener); 162 /** {@see DisplayManagerGlobal#getDisplayInfo} */ getDisplayInfo(int displayId)163 DisplayInfo getDisplayInfo(int displayId); 164 } 165 } 166