Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af16c9b6 authored by Manasi Navare's avatar Manasi Navare Committed by Android (Google) Code Review
Browse files

Merge "Handle onModeRejected display event in DisplayModeDirector" into main

parents e4741059 418c40b5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -93,6 +93,10 @@ public class DisplayManagerFlags {
            com.android.graphics.surfaceflinger.flags.Flags.FLAG_ENABLE_SMALL_AREA_DETECTION,
            com.android.graphics.surfaceflinger.flags.Flags::enableSmallAreaDetection);

    private final FlagState mDisplayConfigErrorHalFlagState = new FlagState(
            com.android.graphics.surfaceflinger.flags.Flags.FLAG_DISPLAY_CONFIG_ERROR_HAL,
            com.android.graphics.surfaceflinger.flags.Flags::displayConfigErrorHal);

    private final FlagState mBrightnessIntRangeUserPerceptionFlagState = new FlagState(
            Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION,
            Flags::brightnessIntRangeUserPerception);
@@ -361,6 +365,10 @@ public class DisplayManagerFlags {
        return mSmallAreaDetectionFlagState.isEnabled();
    }

    public boolean isDisplayConfigErrorHalEnabled() {
        return mDisplayConfigErrorHalFlagState.isEnabled();
    }

    public boolean isBrightnessIntRangeUserPerceptionEnabled() {
        return mBrightnessIntRangeUserPerceptionFlagState.isEnabled();
    }
@@ -591,6 +599,7 @@ public class DisplayManagerFlags {
        pw.println(" " + mPowerThrottlingClamperFlagState);
        pw.println(" " + mEvenDimmerFlagState);
        pw.println(" " + mSmallAreaDetectionFlagState);
        pw.println(" " + mDisplayConfigErrorHalFlagState);
        pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
        pw.println(" " + mRestrictDisplayModes);
        pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
+5 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ public class DisplayModeDirector {
    private final ProximitySensorObserver mSensorObserver;
    private final HbmObserver mHbmObserver;
    private final SkinThermalStatusObserver mSkinThermalStatusObserver;
    private final ModeChangeObserver mModeChangeObserver;

    @Nullable
    private final SystemRequestObserver mSystemRequestObserver;
@@ -247,6 +248,7 @@ public class DisplayModeDirector {
        mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage, injector);
        mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector);
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage);
        mModeChangeObserver = new ModeChangeObserver(mVotesStorage, injector, handler.getLooper());
        mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(),
                mDeviceConfigDisplaySettings);
        if (displayManagerFlags.isRestrictDisplayModesEnabled()) {
@@ -275,6 +277,9 @@ public class DisplayModeDirector {
        mSensorObserver.observe();
        mHbmObserver.observe();
        mSkinThermalStatusObserver.observe();
        if (mDisplayManagerFlags.isDisplayConfigErrorHalEnabled()) {
            mModeChangeObserver.observe();
        }
        synchronized (mLock) {
            // We may have a listener already registered before the call to start, so go ahead and
            // notify them to pick up our newly initialized state.
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.mode;

import android.os.Looper;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayEventReceiver;

import com.android.internal.annotations.KeepForWeakReference;

import java.util.HashSet;
import java.util.Set;

final class ModeChangeObserver {
    private static final String TAG = "ModeChangeObserver";

    private final VotesStorage mVotesStorage;
    private final DisplayModeDirector.Injector mInjector;

    @SuppressWarnings("unused")
    @KeepForWeakReference
    private DisplayEventReceiver mModeChangeListener;
    private final SparseArray<Set<Integer>> mRejectedModesByDisplay = new SparseArray<>();
    private Looper mLooper;

    ModeChangeObserver(VotesStorage votesStorage, DisplayModeDirector.Injector injector,
                    Looper looper) {
        mVotesStorage = votesStorage;
        mInjector = injector;
        mLooper = looper;
    }

    void observe() {
        mModeChangeListener = new DisplayEventReceiver(mLooper) {
            @Override
            public void onModeRejected(long physicalDisplayId, int modeId) {
                Slog.d(TAG, "Mode Rejected event received");
                int displayId = getLogicalDisplayId(physicalDisplayId);
                if (displayId < 0) {
                    Slog.e(TAG, "Logical Display Id not found");
                    return;
                }
                populateRejectedModesListByDisplay(displayId, modeId);
            }

            @Override
            public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
                Slog.d(TAG, "Hotplug event received");
                if (!connected) {
                    int displayId = getLogicalDisplayId(physicalDisplayId);
                    if (displayId < 0) {
                        Slog.e(TAG, "Logical Display Id not found");
                        return;
                    }
                    clearRejectedModesListByDisplay(displayId);
                }
            }
        };
    }

    private int getLogicalDisplayId(long rejectedModePhysicalDisplayId) {
        Display[] displays = mInjector.getDisplays();

        for (Display display : displays) {
            DisplayAddress address = display.getAddress();
            if (address instanceof DisplayAddress.Physical physical) {
                long physicalDisplayId = physical.getPhysicalDisplayId();
                if (physicalDisplayId == rejectedModePhysicalDisplayId) {
                    return display.getDisplayId();
                }
            }
        }
        return -1;
    }

    private void populateRejectedModesListByDisplay(int displayId, int rejectedModeId) {
        Set<Integer> alreadyRejectedModes = mRejectedModesByDisplay.get(displayId);
        if (alreadyRejectedModes == null) {
            alreadyRejectedModes = new HashSet<>();
            mRejectedModesByDisplay.put(displayId, alreadyRejectedModes);
        }
        alreadyRejectedModes.add(rejectedModeId);
        mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES,
                Vote.forRejectedModes(alreadyRejectedModes));
    }

    private void clearRejectedModesListByDisplay(int displayId) {
        mRejectedModesByDisplay.remove(displayId);
        mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, null);
    }
}
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.mode;

import android.annotation.NonNull;

import java.util.Collections;
import java.util.Set;

public class RejectedModesVote implements Vote {

    final Set<Integer> mModeIds;

    RejectedModesVote(Set<Integer> modeIds) {
        mModeIds = Collections.unmodifiableSet(modeIds);
    }
    @Override
    public void updateSummary(@NonNull VoteSummary summary) {
        summary.rejectedModeIds.addAll(mModeIds);
    }

    @Override
    public String toString() {
        return "RejectedModesVote{ mModeIds=" + mModeIds + " }";
    }
}
+28 −15
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

interface Vote {
    // DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
@@ -82,68 +83,73 @@ interface Vote {

    int PRIORITY_APP_REQUEST_SIZE = 7;

    // PRIORITY_REJECTED_MODES rejects the modes for which the mode config failed
    // so that the modeset can be retried for next available mode after filtering
    // out the rejected modes for the connected display
    int PRIORITY_REJECTED_MODES = 8;

    // PRIORITY_USER_SETTING_PEAK_REFRESH_RATE restricts physical refresh rate to
    // [0, max(PEAK, MIN)], depending on user settings peakRR/minRR values
    int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 8;
    int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 9;

    // PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE has a higher priority than
    // PRIORITY_USER_SETTING_PEAK_REFRESH_RATE and will limit render rate to [0, max(PEAK, MIN)]
    // in case physical refresh rate vote is discarded (due to other high priority votes),
    // render rate vote can still apply
    int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 9;
    int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 10;

    // Restrict all displays physical refresh rate to 60Hz when external display is connected.
    // It votes [59Hz, 61Hz].
    int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 10;
    int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 11;

    // PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE has a higher priority than
    // PRIORITY_SYNCHRONIZED_REFRESH_RATE and will limit render rate to [59Hz, 61Hz].
    // In case physical refresh rate vote discarded (due to physical refresh rate not supported),
    // render rate vote can still apply.
    int PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE = 11;
    int PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE = 12;

    // Restrict displays max available resolution and refresh rates. It votes [0, LIMIT]
    int PRIORITY_LIMIT_MODE = 12;
    int PRIORITY_LIMIT_MODE = 13;

    // To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
    // rate to max value (same as for PRIORITY_UDFPS) on lock screen
    int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 13;
    int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 14;

    // For concurrent displays we want to limit refresh rate on all displays
    int PRIORITY_LAYOUT_LIMITED_REFRESH_RATE = 14;
    int PRIORITY_LAYOUT_LIMITED_REFRESH_RATE = 15;

    // For concurrent displays we want to limit refresh rate on all displays
    int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 15;
    int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 16;

    // For internal application to limit display modes to specific ids
    int PRIORITY_SYSTEM_REQUESTED_MODES = 16;
    int PRIORITY_SYSTEM_REQUESTED_MODES = 17;

    // PRIORITY_LOW_POWER_MODE_MODES limits display modes to specific refreshRate-vsync pairs if
    // Settings.Global.LOW_POWER_MODE is on.
    // Lower priority that PRIORITY_LOW_POWER_MODE_RENDER_RATE and if discarded (due to other
    // higher priority votes), render rate limit can still apply
    int PRIORITY_LOW_POWER_MODE_MODES = 17;
    int PRIORITY_LOW_POWER_MODE_MODES = 18;

    // PRIORITY_LOW_POWER_MODE_RENDER_RATE force the render frame rate to [0, 60HZ] if
    // Settings.Global.LOW_POWER_MODE is on.
    int PRIORITY_LOW_POWER_MODE_RENDER_RATE = 18;
    int PRIORITY_LOW_POWER_MODE_RENDER_RATE = 19;

    // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
    // higher priority voters' result is a range, it will fix the rate to a single choice.
    // It's used to avoid refresh rate switches in certain conditions which may result in the
    // user seeing the display flickering when the switches occur.
    int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 19;
    int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 20;

    // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
    int PRIORITY_SKIN_TEMPERATURE = 20;
    int PRIORITY_SKIN_TEMPERATURE = 21;

    // The proximity sensor needs the refresh rate to be locked in order to function, so this is
    // set to a high priority.
    int PRIORITY_PROXIMITY = 21;
    int PRIORITY_PROXIMITY = 22;

    // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
    // to function, so this needs to be the highest priority of all votes.
    int PRIORITY_UDFPS = 22;
    int PRIORITY_UDFPS = 23;

    @IntDef(prefix = { "PRIORITY_" }, value = {
            PRIORITY_DEFAULT_RENDER_FRAME_RATE,
@@ -154,6 +160,7 @@ interface Vote {
            PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE,
            PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
            PRIORITY_APP_REQUEST_SIZE,
            PRIORITY_REJECTED_MODES,
            PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
            PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
            PRIORITY_SYNCHRONIZED_REFRESH_RATE,
@@ -245,6 +252,10 @@ interface Vote {
        return new SupportedModesVote(modeIds);
    }

    static Vote forRejectedModes(Set<Integer> modeIds) {
        return new RejectedModesVote(modeIds);
    }

    static String priorityToString(int priority) {
        switch (priority) {
            case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
@@ -253,6 +264,8 @@ interface Vote {
                return "PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE";
            case PRIORITY_APP_REQUEST_SIZE:
                return "PRIORITY_APP_REQUEST_SIZE";
            case PRIORITY_REJECTED_MODES:
                return "PRIORITY_REJECTED_MODES";
            case PRIORITY_DEFAULT_RENDER_FRAME_RATE:
                return "PRIORITY_DEFAULT_REFRESH_RATE";
            case PRIORITY_FLICKER_REFRESH_RATE:
Loading