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