FrameRateCategory::NoPreference votes Min

LayerVoteType::Min is a vote type that is ignored unless all voting
active layers also vote Min for minimum refresh rate.
Now the NoPreference category works for
infrequent animations such as a blinking cursor.

Bug: 298716564
Test: atest CtsSurfaceControlTestsStaging
Test: atest libsurfaceflinger_unittest
Change-Id: I970d59ff6499b9d64962361f3098d19b6b953d9c
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index e4df494..551d744 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -294,7 +294,7 @@
         if (mLayerVote.category != FrameRateCategory::Default) {
             ALOGV("%s uses frame rate category: %d", mName.c_str(),
                   static_cast<int>(mLayerVote.category));
-            votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, mLayerVote.fps,
+            votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, Fps(),
                              Seamlessness::Default, mLayerVote.category});
         }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 7e77bbe..be28e98 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -501,6 +501,12 @@
                 break;
             case LayerVoteType::ExplicitCategory:
                 explicitCategoryVoteLayers++;
+                if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
+                    // Count this layer for Min vote as well. The explicit vote avoids
+                    // touch boost and idle for choosing a category, while Min vote is for correct
+                    // behavior when all layers are Min or no vote.
+                    minVoteLayers++;
+                }
                 break;
             case LayerVoteType::Heuristic:
                 break;
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b67494f..b7996ce 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -529,7 +529,7 @@
     EXPECT_EQ(1, frequentLayerCount(time));
     // First LayerRequirement is the layer's category specification
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
-    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+    EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
 
     // Second LayerRequirement is the frame rate specification
@@ -544,7 +544,7 @@
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(0, frequentLayerCount(time));
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
-    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+    EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
 }
 
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index e0133d6..11072bc 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -223,8 +223,6 @@
 }
 
 TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) {
-    // When a layer only has a category set, the LayerVoteType should be the LayerInfo's default.
-    // The most common case should be Heuristic.
     LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
                                  .category = FrameRateCategory::High};
     layerInfo.setLayerVote(vote);
@@ -234,6 +232,20 @@
     ASSERT_EQ(actualVotes.size(), 1u);
     ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
     ASSERT_EQ(actualVotes[0].category, vote.category);
+    ASSERT_EQ(actualVotes[0].fps, 0_Hz);
+}
+
+TEST_F(LayerInfoTest, getRefreshRateVote_categoryNoPreference) {
+    LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
+                                 .category = FrameRateCategory::NoPreference};
+    layerInfo.setLayerVote(vote);
+
+    auto actualVotes =
+            layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
+    ASSERT_EQ(actualVotes.size(), 1u);
+    ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
+    ASSERT_EQ(actualVotes[0].category, vote.category);
+    ASSERT_EQ(actualVotes[0].fps, 0_Hz);
 }
 
 TEST_F(LayerInfoTest, getRefreshRateVote_noData) {