diff options
7 files changed, 341 insertions, 227 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 76efce56dcf0..022f3c4c3a20 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1762,6 +1762,24 @@ public final class DisplayManager { * 123,1,critical,0.8,default;123,1,moderate,0.6,id_2;456,2,moderate,0.9,critical,0.7 */ String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data"; + + /** + * Key for new power controller feature flag. If enabled new DisplayPowerController will + * be used. + * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)} + * with {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace. + * @hide + */ + String KEY_NEW_POWER_CONTROLLER = "use_newly_structured_display_power_controller"; + + /** + * Key for normal brightness mode controller feature flag. + * It enables NormalBrightnessModeController. + * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)} + * with {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace. + * @hide + */ + String KEY_USE_NORMAL_BRIGHTNESS_MODE_CONTROLLER = "use_normal_brightness_mode_controller"; } /** diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java index 47cde1517450..5b11cfe7ff06 100644 --- a/services/core/java/com/android/server/display/BrightnessRangeController.java +++ b/services/core/java/com/android/server/display/BrightnessRangeController.java @@ -18,29 +18,42 @@ package com.android.server.display; import android.hardware.display.BrightnessInfo; import android.os.IBinder; +import android.provider.DeviceConfigInterface; + +import com.android.server.display.feature.DeviceConfigParameterProvider; import java.io.PrintWriter; import java.util.function.BooleanSupplier; class BrightnessRangeController { - private static final boolean NBM_FEATURE_FLAG = false; - private final HighBrightnessModeController mHbmController; private final NormalBrightnessModeController mNormalBrightnessModeController = new NormalBrightnessModeController(); private final Runnable mModeChangeCallback; + private final boolean mUseNbmController; + BrightnessRangeController(HighBrightnessModeController hbmController, Runnable modeChangeCallback) { + this(hbmController, modeChangeCallback, + new DeviceConfigParameterProvider(DeviceConfigInterface.REAL)); + } + + BrightnessRangeController(HighBrightnessModeController hbmController, + Runnable modeChangeCallback, DeviceConfigParameterProvider configParameterProvider) { mHbmController = hbmController; mModeChangeCallback = modeChangeCallback; + mUseNbmController = configParameterProvider.isNormalBrightnessControllerFeatureEnabled(); } - void dump(PrintWriter pw) { + pw.println("BrightnessRangeController:"); + pw.println(" mUseNormalBrightnessController=" + mUseNbmController); mHbmController.dump(pw); + mNormalBrightnessModeController.dump(pw); + } void onAmbientLuxChange(float ambientLux) { @@ -90,7 +103,7 @@ class BrightnessRangeController { float getCurrentBrightnessMax() { - if (NBM_FEATURE_FLAG && mHbmController.getHighBrightnessMode() + if (mUseNbmController && mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF) { return Math.min(mHbmController.getCurrentBrightnessMax(), mNormalBrightnessModeController.getCurrentBrightnessMax()); @@ -111,7 +124,7 @@ class BrightnessRangeController { } private void applyChanges(BooleanSupplier nbmChangesFunc, Runnable hbmChangesFunc) { - if (NBM_FEATURE_FLAG) { + if (mUseNbmController) { boolean nbmTransitionChanged = nbmChangesFunc.getAsBoolean(); hbmChangesFunc.run(); // if nbm transition changed - trigger callback diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java index cfdcd636904b..c421ec04d6f5 100644 --- a/services/core/java/com/android/server/display/BrightnessThrottler.java +++ b/services/core/java/com/android/server/display/BrightnessThrottler.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.display.BrightnessInfo; -import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IThermalEventListener; @@ -38,6 +37,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.feature.DeviceConfigParameterProvider; import java.io.PrintWriter; import java.util.ArrayList; @@ -63,7 +63,7 @@ class BrightnessThrottler { private final Runnable mThrottlingChangeCallback; private final SkinThermalStatusObserver mSkinThermalStatusObserver; private final DeviceConfigListener mDeviceConfigListener; - private final DeviceConfigInterface mDeviceConfig; + private final DeviceConfigParameterProvider mConfigParameterProvider; private int mThrottlingStatus; @@ -118,7 +118,7 @@ class BrightnessThrottler { mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mUniqueDisplayId = uniqueDisplayId; - mDeviceConfig = injector.getDeviceConfig(); + mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig()); mDeviceConfigListener = new DeviceConfigListener(); mThermalBrightnessThrottlingDataId = throttlingDataId; mDdcThermalThrottlingDataMap = thermalBrightnessThrottlingDataMap; @@ -145,7 +145,7 @@ class BrightnessThrottler { void stop() { mSkinThermalStatusObserver.stopObserving(); - mDeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListener); + mConfigParameterProvider.removeOnPropertiesChangedListener(mDeviceConfigListener); // We're asked to stop throttling, so reset brightness restrictions. mBrightnessCap = PowerManager.BRIGHTNESS_MAX; mBrightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; @@ -248,12 +248,6 @@ class BrightnessThrottler { mSkinThermalStatusObserver.dump(pw); } - private String getThermalBrightnessThrottlingDataString() { - return mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, - /* defaultValue= */ null); - } - // The brightness throttling data id may or may not be specified in the string that is passed // in, if there is none specified, we assume it is for the default case. Each string passed in // here must be for one display and one throttling id. @@ -318,7 +312,8 @@ class BrightnessThrottler { private void loadThermalBrightnessThrottlingDataFromDeviceConfig() { HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>> tempThrottlingData = new HashMap<>(1); - mThermalBrightnessThrottlingDataString = getThermalBrightnessThrottlingDataString(); + mThermalBrightnessThrottlingDataString = + mConfigParameterProvider.getBrightnessThrottlingData(); boolean validConfig = true; mThermalBrightnessThrottlingDataOverride.clear(); if (mThermalBrightnessThrottlingDataString != null) { @@ -390,8 +385,7 @@ class BrightnessThrottler { public Executor mExecutor = new HandlerExecutor(mDeviceConfigHandler); public void startListening() { - mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - mExecutor, this); + mConfigParameterProvider.addOnPropertiesChangedListener(mExecutor, this); } @Override diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 858800a82151..dbe15b6e2da8 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -24,7 +24,6 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static android.hardware.display.DisplayManager.EventsMask; -import static android.hardware.display.DisplayManager.HDR_OUTPUT_CONTROL_FLAG; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; @@ -42,7 +41,6 @@ import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL; import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_UNSUPPORTED; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.ROOT_UID; -import static android.provider.DeviceConfig.NAMESPACE_DISPLAY_MANAGER; import android.Manifest; import android.annotation.NonNull; @@ -116,7 +114,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; -import android.provider.DeviceConfig; +import android.provider.DeviceConfigInterface; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; @@ -152,6 +150,7 @@ import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.companion.virtual.VirtualDeviceManagerInternal; import com.android.server.display.DisplayDeviceConfig.SensorData; +import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.layout.Layout; import com.android.server.display.mode.DisplayModeDirector; import com.android.server.display.utils.SensorUtils; @@ -506,6 +505,8 @@ public final class DisplayManagerService extends SystemService { private final BrightnessSynchronizer mBrightnessSynchronizer; + private final DeviceConfigParameterProvider mConfigParameterProvider; + /** * Applications use {@link android.view.Display#getRefreshRate} and * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate. @@ -558,6 +559,7 @@ public final class DisplayManagerService extends SystemService { mWideColorSpace = colorSpaces[1]; mOverlayProperties = SurfaceControl.getOverlaySupport(); mSystemReady = false; + mConfigParameterProvider = new DeviceConfigParameterProvider(DeviceConfigInterface.REAL); } public void setupSchedulerPolicies() { @@ -694,11 +696,11 @@ public final class DisplayManagerService extends SystemService { synchronized (mSyncRoot) { mSafeMode = safeMode; mSystemReady = true; - mIsHdrOutputControlEnabled = isDeviceConfigHdrOutputControlEnabled(); - DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_DISPLAY_MANAGER, - BackgroundThread.getExecutor(), + mIsHdrOutputControlEnabled = + mConfigParameterProvider.isHdrOutputControlFeatureEnabled(); + mConfigParameterProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(), properties -> mIsHdrOutputControlEnabled = - isDeviceConfigHdrOutputControlEnabled()); + mConfigParameterProvider.isHdrOutputControlFeatureEnabled()); // Just in case the top inset changed before the system was ready. At this point, any // relevant configuration should be in place. recordTopInsetLocked(mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)); @@ -729,12 +731,6 @@ public final class DisplayManagerService extends SystemService { mContext.registerReceiver(mIdleModeReceiver, filter); } - private boolean isDeviceConfigHdrOutputControlEnabled() { - return DeviceConfig.getBoolean(NAMESPACE_DISPLAY_MANAGER, - HDR_OUTPUT_CONTROL_FLAG, - true); - } - @VisibleForTesting Handler getDisplayHandler() { return mHandler; @@ -3158,8 +3154,7 @@ public final class DisplayManagerService extends SystemService { + "display: " + display.getDisplayIdLocked()); return null; } - if (DeviceConfig.getBoolean("display_manager", - "use_newly_structured_display_power_controller", true)) { + if (mConfigParameterProvider.isNewPowerControllerFeatureEnabled()) { displayPowerController = new DisplayPowerController2( mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler, mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, diff --git a/services/core/java/com/android/server/display/NormalBrightnessModeController.java b/services/core/java/com/android/server/display/NormalBrightnessModeController.java index dbabc2441224..135ebd8f4fbf 100644 --- a/services/core/java/com/android/server/display/NormalBrightnessModeController.java +++ b/services/core/java/com/android/server/display/NormalBrightnessModeController.java @@ -21,6 +21,7 @@ import android.os.PowerManager; import com.android.server.display.DisplayDeviceConfig.BrightnessLimitMapType; +import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; @@ -60,6 +61,14 @@ class NormalBrightnessModeController { return recalculateMaxBrightness(); } + void dump(PrintWriter pw) { + pw.println("NormalBrightnessModeController:"); + pw.println(" mAutoBrightnessEnabled=" + mAutoBrightnessEnabled); + pw.println(" mAmbientLux=" + mAmbientLux); + pw.println(" mMaxBrightness=" + mMaxBrightness); + pw.println(" mMaxBrightnessLimits=" + mMaxBrightnessLimits); + } + private boolean recalculateMaxBrightness() { float foundAmbientBoundary = Float.MAX_VALUE; float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; diff --git a/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java new file mode 100644 index 000000000000..feebdf1b9799 --- /dev/null +++ b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.feature; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.display.DisplayManager; +import android.provider.DeviceConfig; +import android.provider.DeviceConfigInterface; +import android.util.Slog; + +import java.util.concurrent.Executor; + +/** + * Helper class to access all DeviceConfig features for display_manager namespace + * + **/ +public class DeviceConfigParameterProvider { + + private static final String TAG = "DisplayFeatureProvider"; + + private final DeviceConfigInterface mDeviceConfig; + + public DeviceConfigParameterProvider(DeviceConfigInterface deviceConfig) { + mDeviceConfig = deviceConfig; + } + + // feature: revamping_display_power_controller_feature + // parameter: use_newly_structured_display_power_controller + public boolean isNewPowerControllerFeatureEnabled() { + return mDeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_NEW_POWER_CONTROLLER, true); + } + + // feature: hdr_output_control + // parameter: enable_hdr_output_control + public boolean isHdrOutputControlFeatureEnabled() { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.HDR_OUTPUT_CONTROL_FLAG, true); + } + + // feature: flexible_brightness_range_feature + // parameter: normal_brightness_mode_controller_enabled + public boolean isNormalBrightnessControllerFeatureEnabled() { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_USE_NORMAL_BRIGHTNESS_MODE_CONTROLLER, false); + } + + // feature: smooth_display_feature + // parameter: peak_refresh_rate_default + public float getPeakRefreshRateDefault() { + return mDeviceConfig.getFloat(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1); + } + + // Test parameters + // usage e.g.: adb shell device_config put display_manager refresh_rate_in_hbm_sunlight 90 + + // allows to customize brightness throttling data + public String getBrightnessThrottlingData() { + return mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, null); + } + + public int getRefreshRateInHbmSunlight() { + return mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, -1); + } + + public int getRefreshRateInHbmHdr() { + return mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR, -1); + } + + + public int getRefreshRateInHighZone() { + return mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE, -1); + } + + public int getRefreshRateInLowZone() { + return mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE, -1); + } + + /** Return null if no such property or wrong format (not comma separated integers). */ + @Nullable + public int[] getHighAmbientBrightnessThresholds() { + return getIntArrayProperty(DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS); + } + + /** Return null if no such property or wrong format (not comma separated integers). */ + @Nullable + public int[] getHighDisplayBrightnessThresholds() { + return getIntArrayProperty(DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS); + } + + /** Return null if no such property or wrong format (not comma separated integers). */ + @Nullable + public int[] getLowDisplayBrightnessThresholds() { + return getIntArrayProperty(DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS); + } + + /** Return null if no such property or wrong format (not comma separated integers). */ + @Nullable + public int[] getLowAmbientBrightnessThresholds() { + return getIntArrayProperty(DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS); + } + + /** add property change listener to DeviceConfig */ + public void addOnPropertiesChangedListener(Executor executor, + DeviceConfig.OnPropertiesChangedListener listener) { + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + executor, listener); + } + + /** remove property change listener from DeviceConfig */ + public void removeOnPropertiesChangedListener( + DeviceConfig.OnPropertiesChangedListener listener) { + mDeviceConfig.removeOnPropertiesChangedListener(listener); + } + + @Nullable + private int[] getIntArrayProperty(String prop) { + String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop, + null); + + if (strArray != null) { + return parseIntArray(strArray); + } + return null; + } + + @Nullable + private int[] parseIntArray(@NonNull String strArray) { + String[] items = strArray.split(","); + int[] array = new int[items.length]; + + try { + for (int i = 0; i < array.length; i++) { + array[i] = Integer.parseInt(items[i]); + } + } catch (NumberFormatException e) { + Slog.e(TAG, "Incorrect format for array: '" + strArray + "'", e); + array = null; + } + + return array; + } +} diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 18895788e4ec..11e35ce09c28 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -20,6 +20,7 @@ import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLU import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; import static android.os.PowerManager.BRIGHTNESS_INVALID; +import android.annotation.IntegerRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; @@ -68,6 +69,7 @@ import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.display.DisplayDeviceConfig; +import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.utils.AmbientFilter; import com.android.server.display.utils.AmbientFilterFactory; import com.android.server.display.utils.SensorUtils; @@ -84,6 +86,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.concurrent.Callable; +import java.util.function.IntSupplier; /** * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically @@ -117,7 +120,7 @@ public class DisplayModeDirector { private final SensorObserver mSensorObserver; private final HbmObserver mHbmObserver; private final SkinThermalStatusObserver mSkinThermalStatusObserver; - private final DeviceConfigInterface mDeviceConfig; + private final DeviceConfigParameterProvider mConfigParameterProvider; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; @GuardedBy("mLock") @@ -157,7 +160,7 @@ public class DisplayModeDirector { mSupportedModesByDisplay = new SparseArray<>(); mDefaultModeByDisplay = new SparseArray<>(); mAppRequestObserver = new AppRequestObserver(); - mDeviceConfig = injector.getDeviceConfig(); + mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig()); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mSettingsObserver = new SettingsObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler, injector); @@ -681,9 +684,9 @@ public class DisplayModeDirector { synchronized (mLock) { mDefaultDisplayDeviceConfig = displayDeviceConfig; mSettingsObserver.setRefreshRates(displayDeviceConfig, - /* attemptLoadingFromDeviceConfig= */ true); + /* attemptReadFromFeatureParams= */ true); mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig, - /* attemptLoadingFromDeviceConfig= */ true); + /* attemptReadFromFeatureParams= */ true); mBrightnessObserver.reloadLightSensor(displayDeviceConfig); mHbmObserver.setupHdrRefreshRates(displayDeviceConfig); } @@ -1087,7 +1090,7 @@ public class DisplayModeDirector { // reading from the DeviceConfig is an intensive IO operation and having it in the // startup phase where we thrive to keep the latency very low has significant impact. setRefreshRates(/* displayDeviceConfig= */ null, - /* attemptLoadingFromDeviceConfig= */ false); + /* attemptReadFromFeatureParams= */ false); } /** @@ -1095,8 +1098,8 @@ public class DisplayModeDirector { * if missing from DisplayDeviceConfig, and finally fallback to config.xml. */ public void setRefreshRates(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - setDefaultPeakRefreshRate(displayDeviceConfig, attemptLoadingFromDeviceConfig); + boolean attemptReadFromFeatureParams) { + setDefaultPeakRefreshRate(displayDeviceConfig, attemptReadFromFeatureParams); mDefaultRefreshRate = (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger( R.integer.config_defaultRefreshRate) @@ -1113,9 +1116,9 @@ public class DisplayModeDirector { cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/, this); - Float deviceConfigDefaultPeakRefresh = - mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate(); - if (deviceConfigDefaultPeakRefresh != null) { + float deviceConfigDefaultPeakRefresh = + mConfigParameterProvider.getPeakRefreshRateDefault(); + if (deviceConfigDefaultPeakRefresh != -1) { mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh; } @@ -1137,7 +1140,7 @@ public class DisplayModeDirector { synchronized (mLock) { if (defaultPeakRefreshRate == null) { setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, - /* attemptLoadingFromDeviceConfig= */ false); + /* attemptReadFromFeatureParams= */ false); updateRefreshRateSettingLocked(); } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { mDefaultPeakRefreshRate = defaultPeakRefreshRate; @@ -1171,18 +1174,17 @@ public class DisplayModeDirector { } private void setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - Float defaultPeakRefreshRate = null; + boolean attemptReadFromFeatureParams) { + float defaultPeakRefreshRate = -1; - if (attemptLoadingFromDeviceConfig) { + if (attemptReadFromFeatureParams) { try { - defaultPeakRefreshRate = - mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate(); + defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault(); } catch (Exception exception) { // Do nothing } } - if (defaultPeakRefreshRate == null) { + if (defaultPeakRefreshRate == -1) { defaultPeakRefreshRate = (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger( R.integer.config_defaultPeakRefreshRate) @@ -1528,7 +1530,7 @@ public class DisplayModeDirector { mHandler = handler; mInjector = injector; updateBlockingZoneThresholds(/* displayDeviceConfig= */ null, - /* attemptLoadingFromDeviceConfig= */ false); + /* attemptReadFromFeatureParams= */ false); mRefreshRateInHighZone = context.getResources().getInteger( R.integer.config_fixedRefreshRateInHighZone); } @@ -1537,10 +1539,10 @@ public class DisplayModeDirector { * This is used to update the blocking zone thresholds from the DeviceConfig, which * if missing from DisplayDeviceConfig, and finally fallback to config.xml. */ - public void updateBlockingZoneThresholds(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - loadLowBrightnessThresholds(displayDeviceConfig, attemptLoadingFromDeviceConfig); - loadHighBrightnessThresholds(displayDeviceConfig, attemptLoadingFromDeviceConfig); + public void updateBlockingZoneThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig, + boolean attemptReadFromFeatureParams) { + loadLowBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams); + loadHighBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams); } @VisibleForTesting @@ -1579,20 +1581,20 @@ public class DisplayModeDirector { return mRefreshRateInLowZone; } - private void loadLowBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - loadRefreshRateInHighZone(displayDeviceConfig, attemptLoadingFromDeviceConfig); - loadRefreshRateInLowZone(displayDeviceConfig, attemptLoadingFromDeviceConfig); + private void loadLowBrightnessThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig, + boolean attemptReadFromFeatureParams) { + loadRefreshRateInHighZone(displayDeviceConfig, attemptReadFromFeatureParams); + loadRefreshRateInLowZone(displayDeviceConfig, attemptReadFromFeatureParams); mLowDisplayBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(), + () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), R.array.config_brightnessThresholdsOfPeakRefreshRate, - displayDeviceConfig, attemptLoadingFromDeviceConfig); + displayDeviceConfig, attemptReadFromFeatureParams); mLowAmbientBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(), + () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(), () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), R.array.config_ambientThresholdsOfPeakRefreshRate, - displayDeviceConfig, attemptLoadingFromDeviceConfig); + displayDeviceConfig, attemptReadFromFeatureParams); if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) { throw new RuntimeException("display low brightness threshold array and ambient " + "brightness threshold array have different length: " @@ -1604,55 +1606,55 @@ public class DisplayModeDirector { } private void loadRefreshRateInLowZone(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - int refreshRateInLowZone = - (displayDeviceConfig == null) ? mContext.getResources().getInteger( - R.integer.config_defaultRefreshRateInZone) - : displayDeviceConfig.getDefaultLowBlockingZoneRefreshRate(); - if (attemptLoadingFromDeviceConfig) { + boolean attemptReadFromFeatureParams) { + int refreshRateInLowZone = -1; + if (attemptReadFromFeatureParams) { try { - refreshRateInLowZone = mDeviceConfig.getInt( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE, - refreshRateInLowZone); + refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); } catch (Exception exception) { // Do nothing } } + if (refreshRateInLowZone == -1) { + refreshRateInLowZone = (displayDeviceConfig == null) + ? mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInZone) + : displayDeviceConfig.getDefaultLowBlockingZoneRefreshRate(); + } mRefreshRateInLowZone = refreshRateInLowZone; } private void loadRefreshRateInHighZone(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { - int refreshRateInHighZone = - (displayDeviceConfig == null) ? mContext.getResources().getInteger( - R.integer.config_fixedRefreshRateInHighZone) : displayDeviceConfig - .getDefaultHighBlockingZoneRefreshRate(); - if (attemptLoadingFromDeviceConfig) { + boolean attemptReadFromFeatureParams) { + int refreshRateInHighZone = -1; + if (attemptReadFromFeatureParams) { try { - refreshRateInHighZone = mDeviceConfig.getInt( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE, - refreshRateInHighZone); + refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); } catch (Exception exception) { // Do nothing } } + if (refreshRateInHighZone == -1) { + refreshRateInHighZone = (displayDeviceConfig == null) + ? mContext.getResources().getInteger( + R.integer.config_fixedRefreshRateInHighZone) + : displayDeviceConfig.getDefaultHighBlockingZoneRefreshRate(); + } mRefreshRateInHighZone = refreshRateInHighZone; } private void loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig, - boolean attemptLoadingFromDeviceConfig) { + boolean attemptReadFromFeatureParams) { mHighDisplayBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(), + () -> mConfigParameterProvider.getHighDisplayBrightnessThresholds(), () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, - displayDeviceConfig, attemptLoadingFromDeviceConfig); + displayDeviceConfig, attemptReadFromFeatureParams); mHighAmbientBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(), + () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(), () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, - displayDeviceConfig, attemptLoadingFromDeviceConfig); + displayDeviceConfig, attemptReadFromFeatureParams); if (mHighDisplayBrightnessThresholds.length != mHighAmbientBrightnessThresholds.length) { throw new RuntimeException("display high brightness threshold array and ambient " @@ -1668,10 +1670,10 @@ public class DisplayModeDirector { Callable<int[]> loadFromDeviceConfigDisplaySettingsCallable, Callable<int[]> loadFromDisplayDeviceConfigCallable, int brightnessThresholdOfFixedRefreshRateKey, - DisplayDeviceConfig displayDeviceConfig, boolean attemptLoadingFromDeviceConfig) { + DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams) { int[] brightnessThresholds = null; - if (attemptLoadingFromDeviceConfig) { + if (attemptReadFromFeatureParams) { try { brightnessThresholds = loadFromDeviceConfigDisplaySettingsCallable.call(); @@ -1715,9 +1717,9 @@ public class DisplayModeDirector { // DeviceConfig is accessible after system ready. int[] lowDisplayBrightnessThresholds = - mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(); + mConfigParameterProvider.getLowDisplayBrightnessThresholds(); int[] lowAmbientBrightnessThresholds = - mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(); + mConfigParameterProvider.getLowAmbientBrightnessThresholds(); if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null && lowDisplayBrightnessThresholds.length @@ -1727,9 +1729,9 @@ public class DisplayModeDirector { } int[] highDisplayBrightnessThresholds = - mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(); + mConfigParameterProvider.getHighDisplayBrightnessThresholds(); int[] highAmbientBrightnessThresholds = - mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(); + mConfigParameterProvider.getHighAmbientBrightnessThresholds(); if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null && highDisplayBrightnessThresholds.length @@ -1738,14 +1740,12 @@ public class DisplayModeDirector { mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds; } - final int refreshRateInLowZone = mDeviceConfigDisplaySettings - .getRefreshRateInLowZone(); + final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); if (refreshRateInLowZone != -1) { mRefreshRateInLowZone = refreshRateInLowZone; } - final int refreshRateInHighZone = mDeviceConfigDisplaySettings - .getRefreshRateInHighZone(); + final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); if (refreshRateInHighZone != -1) { mRefreshRateInHighZone = refreshRateInHighZone; } @@ -1799,15 +1799,15 @@ public class DisplayModeDirector { displayDeviceConfig = mDefaultDisplayDeviceConfig; } mLowDisplayBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(), + () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), R.array.config_brightnessThresholdsOfPeakRefreshRate, - displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + displayDeviceConfig, /* attemptReadFromFeatureParams= */ false); mLowAmbientBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(), + () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(), () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), R.array.config_ambientThresholdsOfPeakRefreshRate, - displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + displayDeviceConfig, /* attemptReadFromFeatureParams= */ false); } restartObserver(); } @@ -1822,7 +1822,7 @@ public class DisplayModeDirector { // from there. synchronized (mLock) { loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig, - /* attemptLoadingFromDeviceConfig= */ false); + /* attemptReadFromFeatureParams= */ false); } restartObserver(); } else if (refreshRate != mRefreshRateInLowZone) { @@ -1843,15 +1843,15 @@ public class DisplayModeDirector { displayDeviceConfig = mDefaultDisplayDeviceConfig; } mHighDisplayBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(), + () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, - displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + displayDeviceConfig, /* attemptReadFromFeatureParams= */ false); mHighAmbientBrightnessThresholds = loadBrightnessThresholds( - () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(), + () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(), () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, - displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + displayDeviceConfig, /* attemptReadFromFeatureParams= */ false); } restartObserver(); } @@ -1866,7 +1866,7 @@ public class DisplayModeDirector { // from there. synchronized (mLock) { loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig, - /* attemptLoadingFromDeviceConfig= */ false); + /* attemptReadFromFeatureParams= */ false); } restartObserver(); } else if (refreshRate != mRefreshRateInHighZone) { @@ -2675,113 +2675,55 @@ public class DisplayModeDirector { private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public void startListening() { - mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + mConfigParameterProvider.addOnPropertiesChangedListener( BackgroundThread.getExecutor(), this); } - /* - * Return null if no such property or wrong format (not comma separated integers). - */ - public int[] getLowDisplayBrightnessThresholds() { - return getIntArrayProperty( - DisplayManager.DeviceConfig - .KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS); - } - - /* - * Return null if no such property or wrong format (not comma separated integers). - */ - public int[] getLowAmbientBrightnessThresholds() { - return getIntArrayProperty( - DisplayManager.DeviceConfig - .KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS); - } - - public int getRefreshRateInLowZone() { - return mDeviceConfig.getInt( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE, -1); - - } - - /* - * Return null if no such property or wrong format (not comma separated integers). - */ - public int[] getHighDisplayBrightnessThresholds() { - return getIntArrayProperty( - DisplayManager.DeviceConfig - .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS); - } - - /* - * Return null if no such property or wrong format (not comma separated integers). - */ - public int[] getHighAmbientBrightnessThresholds() { - return getIntArrayProperty( - DisplayManager.DeviceConfig - .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS); + private int getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig) { + return getRefreshRate( + () -> mConfigParameterProvider.getRefreshRateInHbmHdr(), + () -> displayDeviceConfig.getDefaultRefreshRateInHbmHdr(), + R.integer.config_defaultRefreshRateInHbmHdr, + displayDeviceConfig + ); } - public int getRefreshRateInHighZone() { - return mDeviceConfig.getInt( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE, - -1); + private int getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig) { + return getRefreshRate( + () -> mConfigParameterProvider.getRefreshRateInHbmSunlight(), + () -> displayDeviceConfig.getDefaultRefreshRateInHbmSunlight(), + R.integer.config_defaultRefreshRateInHbmSunlight, + displayDeviceConfig + ); } - public int getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig) { - int refreshRate = - (displayDeviceConfig == null) ? mContext.getResources().getInteger( - R.integer.config_defaultRefreshRateInHbmHdr) - : displayDeviceConfig.getDefaultRefreshRateInHbmHdr(); + private int getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, + @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig) { + int refreshRate = -1; try { - refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR, - refreshRate); - } catch (NullPointerException e) { + refreshRate = fromConfigPram.getAsInt(); + } catch (NullPointerException npe) { // Do Nothing } - return refreshRate; - } - - public int getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig) { - int refreshRate = - (displayDeviceConfig == null) ? mContext.getResources() - .getInteger(R.integer.config_defaultRefreshRateInHbmSunlight) - : displayDeviceConfig.getDefaultRefreshRateInHbmSunlight(); - try { - refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, - refreshRate); - } catch (NullPointerException e) { - // Do Nothing + if (refreshRate == -1) { + refreshRate = (displayDeviceConfig == null) + ? mContext.getResources().getInteger(configKey) + : fromDisplayDeviceConfig.getAsInt(); } return refreshRate; } - /* - * Return null if no such property - */ - public Float getDefaultPeakRefreshRate() { - float defaultPeakRefreshRate = mDeviceConfig.getFloat( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1); - - if (defaultPeakRefreshRate == -1) { - return null; - } - return defaultPeakRefreshRate; - } - @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { - Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); + float defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault(); mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, - defaultPeakRefreshRate).sendToTarget(); + defaultPeakRefreshRate == -1 ? null : defaultPeakRefreshRate).sendToTarget(); - int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds(); - int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds(); - final int refreshRateInLowZone = getRefreshRateInLowZone(); + int[] lowDisplayBrightnessThresholds = + mConfigParameterProvider.getLowDisplayBrightnessThresholds(); + int[] lowAmbientBrightnessThresholds = + mConfigParameterProvider.getLowAmbientBrightnessThresholds(); + final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED, new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds)) @@ -2790,9 +2732,11 @@ public class DisplayModeDirector { mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0).sendToTarget(); - int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds(); - int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds(); - final int refreshRateInHighZone = getRefreshRateInHighZone(); + int[] highDisplayBrightnessThresholds = + mConfigParameterProvider.getHighDisplayBrightnessThresholds(); + int[] highAmbientBrightnessThresholds = + mConfigParameterProvider.getHighAmbientBrightnessThresholds(); + final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED, new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds)) @@ -2814,33 +2758,6 @@ public class DisplayModeDirector { .sendToTarget(); } } - - private int[] getIntArrayProperty(String prop) { - String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop, - null); - - if (strArray != null) { - return parseIntArray(strArray); - } - - return null; - } - - private int[] parseIntArray(@NonNull String strArray) { - String[] items = strArray.split(","); - int[] array = new int[items.length]; - - try { - for (int i = 0; i < array.length; i++) { - array[i] = Integer.parseInt(items[i]); - } - } catch (NumberFormatException e) { - Slog.e(TAG, "Incorrect format for array: '" + strArray + "'", e); - array = null; - } - - return array; - } } interface Injector { |