1 /* 2 * Copyright (C) 2019 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.server.wm; 18 19 import android.util.ArraySet; 20 import android.view.Display.Mode; 21 import android.view.DisplayInfo; 22 23 /** 24 * Policy to select a lower refresh rate for the display if applicable. 25 */ 26 class RefreshRatePolicy { 27 28 private final int mLowRefreshRateId; 29 private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>(); 30 private final HighRefreshRateBlacklist mHighRefreshRateBlacklist; 31 private final WindowManagerService mWmService; 32 RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateBlacklist blacklist)33 RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, 34 HighRefreshRateBlacklist blacklist) { 35 mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); 36 mHighRefreshRateBlacklist = blacklist; 37 mWmService = wmService; 38 } 39 40 /** 41 * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the 42 * default mode. 43 */ findLowRefreshRateModeId(DisplayInfo displayInfo)44 private int findLowRefreshRateModeId(DisplayInfo displayInfo) { 45 Mode mode = displayInfo.getDefaultMode(); 46 float[] refreshRates = displayInfo.getDefaultRefreshRates(); 47 float bestRefreshRate = mode.getRefreshRate(); 48 for (int i = refreshRates.length - 1; i >= 0; i--) { 49 if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) { 50 bestRefreshRate = refreshRates[i]; 51 } 52 } 53 return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate); 54 } 55 addNonHighRefreshRatePackage(String packageName)56 void addNonHighRefreshRatePackage(String packageName) { 57 mNonHighRefreshRatePackages.add(packageName); 58 mWmService.requestTraversal(); 59 } 60 removeNonHighRefreshRatePackage(String packageName)61 void removeNonHighRefreshRatePackage(String packageName) { 62 mNonHighRefreshRatePackages.remove(packageName); 63 mWmService.requestTraversal(); 64 } 65 getPreferredModeId(WindowState w)66 int getPreferredModeId(WindowState w) { 67 68 // If app is animating, it's not able to control refresh rate because we want the animation 69 // to run in default refresh rate. 70 if (w.isAnimating()) { 71 return 0; 72 } 73 74 // If app requests a certain refresh rate or mode, don't override it. 75 if (w.mAttrs.preferredRefreshRate != 0 || w.mAttrs.preferredDisplayModeId != 0) { 76 return w.mAttrs.preferredDisplayModeId; 77 } 78 79 final String packageName = w.getOwningPackage(); 80 81 // If app is using Camera, force it to default (lower) refresh rate. 82 if (mNonHighRefreshRatePackages.contains(packageName)) { 83 return mLowRefreshRateId; 84 } 85 86 // If app is blacklisted using higher refresh rate, return default (lower) refresh rate 87 if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) { 88 return mLowRefreshRateId; 89 } 90 return 0; 91 } 92 } 93