From ecca8eacbcc1dca821fedf0d5a92cbce925dd0a3 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 29 Mar 2023 22:03:34 -0700 Subject: [PATCH 1/5] Default to using SplitSelectSource drawable if TaskView icon drawable is null * Alternative solution could be to set onTaskViewVisibilityChanged(true) for the taskView that is about to be dismissed so it loads it's taskIcon/thumbnail back from the cache * However, that does still leave us open to race conditions (even though we can be reasonably confident the icon is probably in the cache) * Also made other changes to allow already public fields on some classes to be mockable for unit testing Fixes: 275267738 Test: Tested with fullscreen task at end of overview, GroupedTaskView at end of overview, Initiating split from home, Initiating split from overview actions, Initiating split from overview app icon Change-Id: Ic9059c93c07b90f61c9f418d5d36d6ba201ff96a --- .../uioverrides/QuickstepLauncher.java | 2 +- .../util/SplitAnimationController.kt | 28 ++- .../util/SplitAnimationControllerTest.kt | 165 ++++++++++++++++++ .../util/SplitConfigurationOptions.java | 12 +- 4 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 5e227034be..7318298bef 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -639,7 +639,7 @@ public class QuickstepLauncher extends Launcher { PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration()); RectF startingTaskRect = new RectF(); final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(this, - source.view, null /* thumbnail */, source.drawable, startingTaskRect); + source.getView(), null /* thumbnail */, source.getDrawable(), startingTaskRect); floatingTaskView.setAlpha(1); floatingTaskView.addStagingAnimation(anim, startingTaskRect, tempRect, false /* fadeWithThumbnail */, true /* isStagedTask */); diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index 6dd67def47..b76fe5cb03 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -24,6 +24,7 @@ import android.view.View import com.android.launcher3.DeviceProfile import com.android.launcher3.anim.PendingAnimation import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource +import com.android.quickstep.views.IconView import com.android.quickstep.views.TaskThumbnailView import com.android.quickstep.views.TaskView import com.android.quickstep.views.TaskView.TaskIdAttributeContainer @@ -52,21 +53,22 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * depending on the state of the surface from which the split was initiated */ fun getFirstAnimInitViews(taskViewSupplier: Supplier, - splitSelectSourceSupplier: Supplier) + splitSelectSourceSupplier: Supplier) : SplitAnimInitProps { + val splitSelectSource = splitSelectSourceSupplier.get() if (!splitSelectStateController.isAnimateCurrentTaskDismissal) { // Initiating from home - val splitSelectSource = splitSelectSourceSupplier.get() - return SplitAnimInitProps(splitSelectSource.view, originalBitmap = null, + return SplitAnimInitProps(splitSelectSource!!.view, originalBitmap = null, splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true, iconView = null) } else if (splitSelectStateController.isDismissingFromSplitPair) { // Initiating split from overview, but on a split pair val taskView = taskViewSupplier.get() for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) { - if (container.task.key.id == splitSelectStateController.initialTaskId) { + if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) { + val drawable = getDrawable(container.iconView, splitSelectSource) return SplitAnimInitProps(container.thumbnailView, - container.thumbnailView.thumbnail, container.iconView.drawable!!, + container.thumbnailView.thumbnail, drawable!!, fadeWithThumbnail = true, isStagedTask = true, iconView = container.iconView ) @@ -77,13 +79,27 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC } else { // Initiating split from overview on fullscreen task TaskView val taskView = taskViewSupplier.get() + val drawable = getDrawable(taskView.iconView, splitSelectSource) return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail, - taskView.iconView.drawable!!, fadeWithThumbnail = true, isStagedTask = true, + drawable!!, fadeWithThumbnail = true, isStagedTask = true, taskView.iconView ) } } + /** + * Returns the drawable that's provided in iconView, however if that + * is null it falls back to the drawable that's in splitSelectSource. + * TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen + * @return [Drawable] + */ + fun getDrawable(iconView: IconView, splitSelectSource: SplitSelectSource?) : Drawable? { + if (iconView.drawable == null && splitSelectSource != null) { + return splitSelectSource.drawable + } + return iconView.drawable + } + /** * When selecting first app from split pair, second app's thumbnail remains. This animates * the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt new file mode 100644 index 0000000000..7e07b813a7 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt @@ -0,0 +1,165 @@ +/* + * 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.quickstep.util + +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.launcher3.util.SplitConfigurationOptions +import com.android.quickstep.views.GroupedTaskView +import com.android.quickstep.views.IconView +import com.android.quickstep.views.TaskThumbnailView +import com.android.quickstep.views.TaskView +import com.android.quickstep.views.TaskView.TaskIdAttributeContainer +import com.android.systemui.shared.recents.model.Task +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever + +@RunWith(AndroidJUnit4::class) +class SplitAnimationControllerTest { + + private val taskId = 9 + + @Mock lateinit var mockSplitSelectStateController: SplitSelectStateController + // TaskView + @Mock lateinit var mockTaskView: TaskView + @Mock lateinit var mockThumbnailView: TaskThumbnailView + @Mock lateinit var mockBitmap: Bitmap + @Mock lateinit var mockIconView: IconView + @Mock lateinit var mockTaskViewDrawable: Drawable + // GroupedTaskView + @Mock lateinit var mockGroupedTaskView: GroupedTaskView + @Mock lateinit var mockTask: Task + @Mock lateinit var mockTaskKey: Task.TaskKey + @Mock lateinit var mockTaskIdAttributeContainer: TaskIdAttributeContainer + + // SplitSelectSource + @Mock lateinit var splitSelectSource: SplitConfigurationOptions.SplitSelectSource + @Mock lateinit var mockSplitSourceDrawable: Drawable + @Mock lateinit var mockSplitSourceView: View + + lateinit var splitAnimationController: SplitAnimationController + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + whenever(mockTaskView.thumbnail).thenReturn(mockThumbnailView) + whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap) + whenever(mockTaskView.iconView).thenReturn(mockIconView) + whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable) + + whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable) + whenever(splitSelectSource.view).thenReturn(mockSplitSourceView) + + splitAnimationController = SplitAnimationController(mockSplitSelectStateController) + } + + @Test + fun getFirstAnimInitViews_nullTaskViewIcon_useSplitSourceIcon() { + // Hit fullscreen task dismissal state + whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true) + whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false) + + // Missing taskView icon + whenever(mockIconView.drawable).thenReturn(null) + + val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps = + splitAnimationController.getFirstAnimInitViews( + { mockTaskView }, { splitSelectSource }) + + assertEquals("Did not fallback to use splitSource icon drawable", + mockSplitSourceDrawable, splitAnimInitProps.iconDrawable) + } + + @Test + fun getFirstAnimInitViews_validTaskViewIcon_useTaskViewIcon() { + // Hit fullscreen task dismissal state + whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true) + whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false) + + val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps = + splitAnimationController.getFirstAnimInitViews( + { mockTaskView }, { splitSelectSource }) + + assertEquals("Did not use taskView icon drawable", mockTaskViewDrawable, + splitAnimInitProps.iconDrawable) + } + + @Test + fun getFirstAnimInitViews_validTaskViewNullSplitSource_useTaskViewIcon() { + // Hit fullscreen task dismissal state + whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true) + whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false) + + // Set split source to null + whenever(splitSelectSource.drawable).thenReturn(null) + + val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps = + splitAnimationController.getFirstAnimInitViews( + { mockTaskView }, { splitSelectSource }) + + assertEquals("Did not use taskView icon drawable", mockTaskViewDrawable, + splitAnimInitProps.iconDrawable) + } + + @Test + fun getFirstAnimInitViews_nullTaskViewValidSplitSource_noTaskDismissal() { + // Hit initiating split from home + whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(false) + whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false) + + val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps = + splitAnimationController.getFirstAnimInitViews( + { mockTaskView }, { splitSelectSource }) + + assertEquals("Did not use splitSource icon drawable", mockSplitSourceDrawable, + splitAnimInitProps.iconDrawable) + } + + @Test + fun getFirstAnimInitViews_nullTaskViewValidSplitSource_groupedTaskView() { + // Hit groupedTaskView dismissal + whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true) + whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(true) + + // Remove icon view from GroupedTaskView + whenever(mockIconView.drawable).thenReturn(null) + + whenever(mockTaskIdAttributeContainer.task).thenReturn(mockTask) + whenever(mockTaskIdAttributeContainer.iconView).thenReturn(mockIconView) + whenever(mockTaskIdAttributeContainer.thumbnailView).thenReturn(mockThumbnailView) + whenever(mockTask.getKey()).thenReturn(mockTaskKey) + whenever(mockTaskKey.getId()).thenReturn(taskId) + whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId) + whenever(mockGroupedTaskView.taskIdAttributeContainers) + .thenReturn(Array(1) { mockTaskIdAttributeContainer }) + val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps = + splitAnimationController.getFirstAnimInitViews( + { mockGroupedTaskView }, { splitSelectSource }) + + assertEquals("Did not use splitSource icon drawable", mockSplitSourceDrawable, + splitAnimInitProps.iconDrawable) + } +} \ No newline at end of file diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java index 8c5e78295b..1ae43d000b 100644 --- a/src/com/android/launcher3/util/SplitConfigurationOptions.java +++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java @@ -200,8 +200,8 @@ public final class SplitConfigurationOptions { /** Keep in sync w/ ActivityTaskManager#INVALID_TASK_ID (unreference-able) */ private static final int INVALID_TASK_ID = -1; - public final View view; - public final Drawable drawable; + private View view; + private Drawable drawable; public final Intent intent; public final SplitPositionOption position; public final ItemInfo itemInfo; @@ -224,5 +224,13 @@ public final class SplitConfigurationOptions { this.itemInfo = itemInfo; this.splitEvent = splitEvent; } + + public Drawable getDrawable() { + return drawable; + } + + public View getView() { + return view; + } } } From dcefed1c98fb30349f14584ff9fade0b9b61145d Mon Sep 17 00:00:00 2001 From: Fengjiang Li Date: Thu, 30 Mar 2023 15:55:56 -0700 Subject: [PATCH 2/5] [Predictive Back] Gate feature under experiment flag As predictive back will be launched for U-QPR, we should gate it to avoid it leaked to U launch. Test: turn on/off ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION flag and verify predicitive back is turned on/off Bug: 264920023 Change-Id: Ieee14ca9d49f052f183d8734d62443b890210544 --- .../com/android/launcher3/uioverrides/QuickstepLauncher.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 6475b740d2..dfac37f17d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -745,6 +745,10 @@ public class QuickstepLauncher extends Launcher { @Override protected void registerBackDispatcher() { + if (!FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) { + super.registerBackDispatcher(); + return; + } getOnBackInvokedDispatcher().registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, new OnBackAnimationCallback() { From ba3f77be7de7866bdb65ec81a5597cd053ef0efe Mon Sep 17 00:00:00 2001 From: fbaron Date: Mon, 27 Mar 2023 17:06:52 -0700 Subject: [PATCH 3/5] Show suggested widgets header only when there are suggested widgets Bug: 275435999 Test: Verified suggested widgets header doesn't show up unless there are suggested widgets to show Change-Id: I2ec2ba100d7a6ddc338a36ece75633abba990b2b --- .../widget/picker/WidgetsFullSheet.java | 13 ++--- .../widget/picker/WidgetsTwoPaneSheet.java | 55 ++++++++++++------- .../com/android/launcher3/tapl/Widgets.java | 19 +++++-- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index 5293c3dda0..2325376ebb 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -110,6 +110,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet entry -> !mCurrentUser.equals(entry.mPkgItem.user) && !mUserManagerState.isUserQuiet(entry.mPkgItem.user); protected final boolean mHasWorkProfile; + protected boolean mHasRecommendedWidgets; protected final SparseArray mAdapters = new SparseArray(); @Nullable private ArrowTipView mLatestEducationalTip; private final OnLayoutChangeListener mLayoutChangeListenerToShowTips = @@ -537,7 +538,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet public void onSearchResults(List entries) { mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries); updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH)); - mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop(); } protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) { @@ -574,7 +574,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet } List recommendedWidgets = mActivityContext.getPopupDataProvider().getRecommendedWidgets(); - if (recommendedWidgets.size() > 0) { + mHasRecommendedWidgets = recommendedWidgets.size() > 0; + if (mHasRecommendedWidgets) { float noWidgetsViewHeight = 0; if (mIsNoWidgetsViewNeeded) { // Make sure recommended section leaves enough space for noWidgetsView. @@ -603,14 +604,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet mRecommendedWidgetsTable.setRecommendedWidgets( recommendedWidgetsInTable, maxTableHeight); } else { - hideRecommendations(); + mRecommendedWidgetsTable.setVisibility(GONE); } } - protected void hideRecommendations() { - mRecommendedWidgetsTable.setVisibility(GONE); - } - protected float getMaxTableHeight(float noWidgetsViewHeight) { return (mContent.getMeasuredHeight() - mTabsHeight - getHeaderViewHeight() @@ -896,7 +893,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet final WidgetsListAdapter mWidgetsListAdapter; private final DefaultItemAnimator mWidgetsListItemAnimator; - private WidgetsRecyclerView mWidgetsRecyclerView; + WidgetsRecyclerView mWidgetsRecyclerView; AdapterHolder(int adapterType) { mAdapterType = adapterType; diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java index 2199473e82..46aae9d425 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java @@ -54,6 +54,7 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { private ScrollView mRightPaneScrollView; private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder; + private int mActivePage = -1; private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() { @Override @@ -107,7 +108,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view); mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER); - setupSuggestedWidgets(layoutInflater); onRecommendedWidgetsBound(); onWidgetsBound(); setUpEducationViewsIfNeeded(); @@ -117,9 +117,13 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { } @Override - protected void hideRecommendations() { - super.hideRecommendations(); - mSuggestedWidgetsContainer.setVisibility(GONE); + public void onRecommendedWidgetsBound() { + super.onRecommendedWidgetsBound(); + + if (mSuggestedWidgetsContainer == null && mHasRecommendedWidgets) { + setupSuggestedWidgets(LayoutInflater.from(getContext())); + mSuggestedWidgetsHeader.callOnClick(); + } } private void setupSuggestedWidgets(LayoutInflater layoutInflater) { @@ -168,13 +172,21 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { @Override public void onActivePageChanged(int currentActivePage) { - // if the current active page changes to personal or work we set suggestions - // to be the selected widget - if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) { - mSuggestedWidgetsHeader.callOnClick(); + super.onActivePageChanged(currentActivePage); + + // If active page didn't change then we don't want to update the header. + if (mActivePage == currentActivePage) { + return; } - super.onActivePageChanged(currentActivePage); + mActivePage = currentActivePage; + + if (mSuggestedWidgetsHeader == null) { + mAdapters.get(currentActivePage).mWidgetsListAdapter.selectFirstHeaderEntry(); + mAdapters.get(currentActivePage).mWidgetsRecyclerView.scrollToTop(); + } else if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) { + mSuggestedWidgetsHeader.callOnClick(); + } } @Override @@ -187,16 +199,11 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { super.updateRecyclerViewVisibility(adapterHolder); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mSuggestedWidgetsContainer.setVisibility(VISIBLE); - } - @Override public void onSearchResults(List entries) { super.onSearchResults(entries); mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry(); + mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop(); } @Override @@ -208,13 +215,19 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { @Override protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) { - if (isInSearchMode) { - mSuggestedWidgetsContainer.setVisibility(GONE); - } else { - mSuggestedWidgetsContainer.setVisibility(VISIBLE); - mSuggestedWidgetsHeader.callOnClick(); - } super.setViewVisibilityBasedOnSearch(isInSearchMode); + + if (mSuggestedWidgetsHeader != null && mSuggestedWidgetsContainer != null) { + if (!isInSearchMode) { + mSuggestedWidgetsContainer.setVisibility(VISIBLE); + mSuggestedWidgetsHeader.callOnClick(); + } else { + mSuggestedWidgetsContainer.setVisibility(GONE); + } + } else if (!isInSearchMode) { + mAdapters.get(mActivePage).mWidgetsListAdapter.selectFirstHeaderEntry(); + } + } @Override diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index c1c26ec901..79b54ba0a3 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -182,12 +182,6 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { UiObject2 widgetListView = verifyActiveContainer(); UiObject2 header = mLauncher.waitForObjectInContainer(widgetListView, headerSelector); - // If we are in a tablet in landscape mode then we will have a two pane view and we use - // the right pane to display the widgets table. - UiObject2 rightPane = mLauncher.findObjectInContainer( - widgetPicker, - widgetsContainerSelector); - // If a header is barely visible in the bottom edge of the screen, its height could be // too small for a scroll gesture. Since all header should have roughly the same height, // let's pick the max height we have seen so far. @@ -209,6 +203,12 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { mLauncher.clickLauncherObject(headerTitle); } + // If we are in a tablet in landscape mode then we will have a two pane view and we + // use the right pane to display the widgets table. + UiObject2 rightPane = mLauncher.findObjectInContainer( + widgetPicker, + widgetsContainerSelector); + // Look for a widgets list. UiObject2 widgetsContainer = mLauncher.findObjectInContainer( rightPane != null ? rightPane : widgetListView, @@ -219,6 +219,13 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } } log("Finding test widget package - scroll with distance: " + scrollDistance); + + // If we are in a tablet in landscape mode then we will have a two pane view and we use + // the right pane to display the widgets table. + UiObject2 rightPane = mLauncher.findObjectInContainer( + widgetPicker, + widgetsContainerSelector); + mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null ? rightPane : widgetListView, scrollDistance); From 04ac8c8796d2cf6ea76028aeee04183d5807e305 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 31 Mar 2023 18:16:59 -0700 Subject: [PATCH 4/5] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I5872e217608d63e4c22ad6c26ab14ca80b0863fc --- res/values-uz/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index f53aaf4d9b..30e6b8bf71 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -106,7 +106,7 @@ "Telefon burilganda" "Bildirishnoma belgilari" "Yoniq" - "Yoqilmagan" + "Oʻchiq" "Bildirishnomalarga ruxsat berilmagan" "Bildirishnoma belgilarini ko‘rsatish uchun %1$s ilovasida bildirishnomalarni yoqing" "Sozlamalarni o‘zgartirish" From ef6b0c070037ff79acb637fab73df7122e6822be Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 20 Mar 2023 15:56:07 -0700 Subject: [PATCH 5/5] Adding a Teamfood flag option This allows a targetting a collection of flags to a specific group either using rollout or via opt-in Flag: N/A Bug: 274517185 Test: Verified that the team food flag controls dependent-flags Change-Id: I7e02964d778e3fbf54eda0f34bab8ec5a1206e40 --- .../uioverrides/flags/DebugFlag.java | 8 +- .../flags/DeveloperOptionsFragment.java | 10 +- .../uioverrides/flags/DeviceFlag.java | 4 +- .../uioverrides/flags/FlagTogglerPrefUi.java | 55 +++-- .../uioverrides/flags/FlagsFactory.java | 66 ++++-- .../launcher3/config/FeatureFlags.java | 220 +++++++++--------- .../uioverrides/flags/FlagsFactory.java | 11 +- 7 files changed, 223 insertions(+), 151 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java index d4944d0315..481e20007e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java @@ -15,16 +15,20 @@ */ package com.android.launcher3.uioverrides.flags; +import androidx.annotation.NonNull; + import com.android.launcher3.config.FeatureFlags.BooleanFlag; +import com.android.launcher3.config.FeatureFlags.FlagState; class DebugFlag extends BooleanFlag { public final String key; public final String description; - public final boolean defaultValue; + @NonNull + public final FlagState defaultValue; - public DebugFlag(String key, String description, boolean defaultValue, boolean currentValue) { + DebugFlag(String key, String description, FlagState defaultValue, boolean currentValue) { super(currentValue); this.key = key; this.defaultValue = defaultValue; diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java index 67ea1af056..89aba90335 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java @@ -39,6 +39,7 @@ import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.ArrayMap; import android.util.Pair; @@ -182,9 +183,16 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } private PreferenceCategory newCategory(String title) { + return newCategory(title, null); + } + + private PreferenceCategory newCategory(String title, @Nullable String summary) { PreferenceCategory category = new PreferenceCategory(getContext()); category.setOrder(Preference.DEFAULT_ORDER); category.setTitle(title); + if (!TextUtils.isEmpty(summary)) { + category.setSummary(summary); + } mPreferenceScreen.addPreference(category); return category; } @@ -195,7 +203,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } mFlagTogglerPrefUi = new FlagTogglerPrefUi(this); - mFlagTogglerPrefUi.applyTo(newCategory("Feature flags")); + mFlagTogglerPrefUi.applyTo(newCategory("Feature flags", "Long press to reset")); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java index 3900ebb549..035beb4df1 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java @@ -16,11 +16,13 @@ package com.android.launcher3.uioverrides.flags; +import com.android.launcher3.config.FeatureFlags.FlagState; + class DeviceFlag extends DebugFlag { private final boolean mDefaultValueInCode; - public DeviceFlag(String key, String description, boolean defaultValue, + DeviceFlag(String key, String description, FlagState defaultValue, boolean currentValue, boolean defaultValueInCode) { super(key, description, defaultValue, currentValue); mDefaultValueInCode = defaultValueInCode; diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java index b7fb2ed827..9c59361431 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java @@ -17,11 +17,15 @@ package com.android.launcher3.uioverrides.flags; import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME; +import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; +import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG; import android.content.Context; import android.content.SharedPreferences; +import android.os.Handler; import android.os.Process; import android.text.Html; +import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -30,6 +34,7 @@ import android.widget.Toast; import androidx.preference.PreferenceDataStore; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; import com.android.launcher3.R; @@ -59,12 +64,7 @@ public final class FlagTogglerPrefUi { @Override public boolean getBoolean(String key, boolean defaultValue) { - for (DebugFlag flag : FlagsFactory.getDebugFlags()) { - if (flag.key.equals(key)) { - return mSharedPreferences.getBoolean(key, flag.defaultValue); - } - } - return defaultValue; + return mSharedPreferences.getBoolean(key, defaultValue); } }; @@ -87,18 +87,41 @@ public final class FlagTogglerPrefUi { : f1.key.compareToIgnoreCase(f2.key); }); + // Ensure that teamfood flag comes on the top + if (flags.remove(TEAMFOOD_FLAG)) { + flags.add(0, (DebugFlag) TEAMFOOD_FLAG); + } + // For flag overrides we only want to store when the engineer chose to override the // flag with a different value than the default. That way, when we flip flags in // future, engineers will pick up the new value immediately. To accomplish this, we use a // custom preference data store. for (DebugFlag flag : flags) { - SwitchPreference switchPreference = new SwitchPreference(mContext); + SwitchPreference switchPreference = new SwitchPreference(mContext) { + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.itemView.setOnLongClickListener(v -> { + mSharedPreferences.edit().remove(flag.key).apply(); + setChecked(getFlagStateFromSharedPrefs(flag)); + updateSummary(this, flag); + updateMenu(); + return true; + }); + } + }; switchPreference.setKey(flag.key); - switchPreference.setDefaultValue(flag.defaultValue); + switchPreference.setDefaultValue(FlagsFactory.getEnabledValue(flag.defaultValue)); switchPreference.setChecked(getFlagStateFromSharedPrefs(flag)); switchPreference.setTitle(flag.key); updateSummary(switchPreference, flag); switchPreference.setPreferenceDataStore(mDataStore); + switchPreference.setOnPreferenceChangeListener((p, v) -> { + new Handler().post(() -> updateSummary(switchPreference, flag)); + return true; + }); + + parent.addPreference(switchPreference); } updateMenu(); @@ -108,10 +131,15 @@ public final class FlagTogglerPrefUi { * Updates the summary to show the description and whether the flag overrides the default value. */ private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) { - String onWarning = flag.defaultValue ? "" : "OVERRIDDEN
"; - String offWarning = flag.defaultValue ? "OVERRIDDEN
" : ""; - switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.description)); - switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.description)); + String summary = flag.defaultValue == TEAMFOOD + ? "[TEAMFOOD] " : ""; + if (mSharedPreferences.contains(flag.key)) { + summary += "[OVERRIDDEN] "; + } + if (!TextUtils.isEmpty(summary)) { + summary += "
"; + } + switchPreference.setSummary(Html.fromHtml(summary + flag.description)); } private void updateMenu() { @@ -143,7 +171,8 @@ public final class FlagTogglerPrefUi { } private boolean getFlagStateFromSharedPrefs(DebugFlag flag) { - return mDataStore.getBoolean(flag.key, flag.defaultValue); + boolean defaultValue = FlagsFactory.getEnabledValue(flag.defaultValue); + return mDataStore.getBoolean(flag.key, defaultValue); } private boolean anyChanged() { diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java index f748e8a3e8..d066abe335 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java @@ -18,6 +18,10 @@ package com.android.launcher3.uioverrides.flags; import static android.app.ActivityThread.currentApplication; +import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE; +import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED; +import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED; +import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.Context; @@ -26,8 +30,8 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.util.Log; -import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags.BooleanFlag; +import com.android.launcher3.config.FeatureFlags.FlagState; import com.android.launcher3.config.FeatureFlags.IntFlag; import com.android.launcher3.util.ScreenOnTracker; @@ -53,6 +57,9 @@ public class FlagsFactory { private static final List sDebugFlags = new ArrayList<>(); + static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag( + 0, "LAUNCHER_TEAMFOOD", DISABLED, "Enable this flag to opt-in all team food flags"); + private final Set mKeySet = new HashSet<>(); private boolean mRestartRequested = false; @@ -64,35 +71,54 @@ public class FlagsFactory { NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged); } - /** - * Creates a new debug flag - */ - public static BooleanFlag getDebugFlag( - int bugId, String key, boolean defaultValue, String description) { - if (Utilities.IS_DEBUG_DEVICE) { - SharedPreferences prefs = currentApplication() - .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); - boolean currentValue = prefs.getBoolean(key, defaultValue); - DebugFlag flag = new DebugFlag(key, description, defaultValue, currentValue); - sDebugFlags.add(flag); - return flag; + static boolean getEnabledValue(FlagState flagState) { + if (IS_DEBUG_DEVICE) { + switch (flagState) { + case ENABLED: + return true; + case TEAMFOOD: + return TEAMFOOD_FLAG.get(); + default: + return false; + } } else { - return new BooleanFlag(defaultValue); + return flagState == ENABLED; } } /** - * Creates a new release flag + * Creates a new debug flag. Debug flags always take their default value in release builds. On + * dogfood builds, they can be manually turned on using the flag toggle UI. + */ + public static BooleanFlag getDebugFlag( + int bugId, String key, FlagState flagState, String description) { + if (IS_DEBUG_DEVICE) { + SharedPreferences prefs = currentApplication() + .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); + boolean defaultValue = getEnabledValue(flagState); + boolean currentValue = prefs.getBoolean(key, defaultValue); + DebugFlag flag = new DebugFlag(key, description, flagState, currentValue); + sDebugFlags.add(flag); + return flag; + } else { + return new BooleanFlag(getEnabledValue(flagState)); + } + } + + /** + * Creates a new release flag. Release flags can be rolled out using server configurations and + * also allow manual overrides on debug builds. */ public static BooleanFlag getReleaseFlag( - int bugId, String key, boolean defaultValueInCode, String description) { + int bugId, String key, FlagState flagState, String description) { INSTANCE.mKeySet.add(key); + boolean defaultValueInCode = getEnabledValue(flagState); boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode); - if (Utilities.IS_DEBUG_DEVICE) { + if (IS_DEBUG_DEVICE) { SharedPreferences prefs = currentApplication() .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); boolean currentValue = prefs.getBoolean(key, defaultValue); - DebugFlag flag = new DeviceFlag(key, description, defaultValue, currentValue, + DebugFlag flag = new DeviceFlag(key, description, flagState, currentValue, defaultValueInCode); sDebugFlags.add(flag); return flag; @@ -111,7 +137,7 @@ public class FlagsFactory { } static List getDebugFlags() { - if (!Utilities.IS_DEBUG_DEVICE) { + if (!IS_DEBUG_DEVICE) { return Collections.emptyList(); } synchronized (sDebugFlags) { @@ -123,7 +149,7 @@ public class FlagsFactory { * Dumps the current flags state to the print writer */ public static void dump(PrintWriter pw) { - if (!Utilities.IS_DEBUG_DEVICE) { + if (!IS_DEBUG_DEVICE) { return; } pw.println("DeviceFlags:"); diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 2972489dc1..8cde18d0f4 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -16,6 +16,9 @@ package com.android.launcher3.config; +import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED; +import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED; +import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag; import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag; @@ -74,338 +77,326 @@ public final class FeatureFlags { * and set a default value for the flag. This will be the default value on Debug builds. */ public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag(270390028, - "ENABLE_INPUT_CONSUMER_REASON_LOGGING", - true, + "ENABLE_INPUT_CONSUMER_REASON_LOGGING", ENABLED, "Log the reason why an Input Consumer was selected for a gesture."); public static final BooleanFlag ENABLE_GESTURE_ERROR_DETECTION = getDebugFlag(270389990, - "ENABLE_GESTURE_ERROR_DETECTION", - true, + "ENABLE_GESTURE_ERROR_DETECTION", ENABLED, "Analyze gesture events and log detected errors"); // When enabled the promise icon is visible in all apps while installation an app. public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012, - "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps"); + "PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps"); public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904, - "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper"); + "KEYGUARD_ANIMATION", DISABLED, + "Enable animation for keyguard going away on wallpaper"); public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907, - "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps"); + "ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps"); public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR = - getReleaseFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", false, - "Keep All Apps search bar at the bottom (but above keyboard if open)"); + getReleaseFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", DISABLED, + "Keep All Apps search bar at the bottom (but above keyboard if open)"); public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930, - "ENABLE_HIDE_HEADER", true, "Hide header on keyboard before typing in all apps"); + "ENABLE_HIDE_HEADER", ENABLED, "Hide header on keyboard before typing in all apps"); public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getDebugFlag(270390779, - "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false, + "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED, "Expand and collapse pause work button while scrolling"); public static final BooleanFlag COLLECT_SEARCH_HISTORY = getReleaseFlag(270391455, - "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log"); + "COLLECT_SEARCH_HISTORY", DISABLED, "Allow launcher to collect search history for log"); public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937, - "ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps."); + "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps."); public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851, - "ENABLE_TWOLINE_DEVICESEARCH", false, + "ENABLE_TWOLINE_DEVICESEARCH", DISABLED, "Enable two line label for icons with labels on device search."); public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = getReleaseFlag( - 270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", false, + 270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", DISABLED, "Allows on device search in all apps logging"); public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693, - "IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps"); + "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps"); public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653, - "ENABLE_PEOPLE_TILE_PREVIEW", false, + "ENABLE_PEOPLE_TILE_PREVIEW", DISABLED, "Experimental: Shows conversation shortcuts on home screen as search results"); public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638, - "FOLDER_NAME_MAJORITY_RANKING", true, + "FOLDER_NAME_MAJORITY_RANKING", ENABLED, "Suggests folder names based on majority based ranking."); public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706, - "INJECT_FALLBACK_APP_CORPUS_RESULTS", false, + "INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED, "Inject fallback app corpus result when AiAi fails to return it."); public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(270391641, - "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, + "ASSISTANT_GIVES_LAUNCHER_FOCUS", DISABLED, "Allow Launcher to handle nav bar gestures while Assistant is running over it"); public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag(270392203, - "ENABLE_BULK_WORKSPACE_ICON_LOADING", - true, + "ENABLE_BULK_WORKSPACE_ICON_LOADING", ENABLED, "Enable loading workspace icons in bulk."); public static final BooleanFlag ENABLE_BULK_ALL_APPS_ICON_LOADING = getDebugFlag(270392465, - "ENABLE_BULK_ALL_APPS_ICON_LOADING", - true, - "Enable loading all apps icons in bulk."); + "ENABLE_BULK_ALL_APPS_ICON_LOADING", ENABLED, "Enable loading all apps icons in bulk."); public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(270392706, - "ENABLE_DATABASE_RESTORE", false, + "ENABLE_DATABASE_RESTORE", DISABLED, "Enable database restore when new restore session is created"); public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(270391664, - "ENABLE_SMARTSPACE_DISMISS", true, + "ENABLE_SMARTSPACE_DISMISS", ENABLED, "Adds a menu option to dismiss the current Enhanced Smartspace card."); public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(270392629, - "ENABLE_OVERLAY_CONNECTION_OPTIM", - false, + "ENABLE_OVERLAY_CONNECTION_OPTIM", DISABLED, "Enable optimizing overlay service connection"); /** * Enables region sampling for text color: Needs system health assessment before turning on */ public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag(270391669, - "ENABLE_REGION_SAMPLING", false, + "ENABLE_REGION_SAMPLING", DISABLED, "Enable region sampling to determine color of text on screen."); public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS = - getDebugFlag(270393096, - "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false, - "Always use hardware optimization for folder animations."); + getDebugFlag(270393096, "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", + DISABLED, "Always use hardware optimization for folder animations."); public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(270392980, - "SEPARATE_RECENTS_ACTIVITY", false, + "SEPARATE_RECENTS_ACTIVITY", DISABLED, "Uses a separate recents activity instead of using the integrated recents+Launcher UI"); public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(270392984, - "ENABLE_MINIMAL_DEVICE", false, + "ENABLE_MINIMAL_DEVICE", DISABLED, "Allow user to toggle minimal device mode in launcher."); - public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag( - 270392477, "ENABLE_TASKBAR_POPUP_MENU", true, + public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag(270392477, + "ENABLE_TASKBAR_POPUP_MENU", ENABLED, "Enables long pressing taskbar icons to show the popup menu."); public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag(270392643, - "ENABLE_TWO_PANEL_HOME", true, + "ENABLE_TWO_PANEL_HOME", ENABLED, "Uses two panel on home screen. Only applicable on large screen devices."); public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276, - "ENABLE_SCRIM_FOR_APP_LAUNCH", false, - "Enables scrim during app launch animation."); + "ENABLE_SCRIM_FOR_APP_LAUNCH", DISABLED, "Enables scrim during app launch animation."); public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258, - "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets"); + "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED, + "Enforce rounded corners on all App Widgets"); - public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag( - 270393108, "NOTIFY_CRASHES", false, - "Sends a notification whenever launcher encounters an uncaught exception."); + public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES", + DISABLED, "Sends a notification whenever launcher encounters an uncaught exception."); public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(270393604, - "ENABLE_WALLPAPER_SCRIM", false, + "ENABLE_WALLPAPER_SCRIM", DISABLED, "Enables scrim over wallpaper for text protection."); public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(270393268, - "WIDGETS_IN_LAUNCHER_PREVIEW", true, + "WIDGETS_IN_LAUNCHER_PREVIEW", ENABLED, "Enables widgets in Launcher preview for the Wallpaper app."); public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag(270393112, - "QUICK_WALLPAPER_PICKER", true, - "Shows quick wallpaper picker in long-press menu"); + "QUICK_WALLPAPER_PICKER", ENABLED, "Shows quick wallpaper picker in long-press menu"); public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426, - "ENABLE_BACK_SWIPE_HOME_ANIMATION", true, + "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED, "Enables home animation to icon when user swipes back."); public static final BooleanFlag ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION = getDebugFlag(270614790, - "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", false, + "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED, "Enables predictive back aniamtion from all apps and widgets to home"); public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(270393294, - "ENABLE_ICON_LABEL_AUTO_SCALING", true, + "ENABLE_ICON_LABEL_AUTO_SCALING", ENABLED, "Enables scaling/spacing for icon labels to make more characters visible"); public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897, - "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", false, + "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED, "Enables displaying the all apps button in the hotseat."); public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(270393900, - "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false, + "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", DISABLED, "Enables One Search box in Taskbar All Apps."); public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(270393906, - "ENABLE_SPLIT_FROM_WORKSPACE", true, + "ENABLE_SPLIT_FROM_WORKSPACE", ENABLED, "Enable initiating split screen from workspace."); public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS = - getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", true, - "Enable splitting from fullscreen app with keyboard shortcuts"); + getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", ENABLED, + "Enable splitting from fullscreen app with keyboard shortcuts"); public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag( - 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false, + 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED, "Enable initiating split screen from workspace to workspace."); public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455, - "ENABLE_NEW_MIGRATION_LOGIC", true, + "ENABLE_NEW_MIGRATION_LOGIC", ENABLED, "Enable the new grid migration logic, keeping pages when src < dest"); public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384, - "ENABLE_WIDGET_HOST_IN_BACKGROUND", true, + "ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED, "Enable background widget updates listening for widget holder"); public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = getReleaseFlag(270394223, - "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch."); + "ENABLE_ONE_SEARCH_MOTION", ENABLED, "Enables animations in OneSearch."); public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag( - 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false, + 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", DISABLED, "Enable option to replace decorator-based search result backgrounds with drawables"); public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag( - 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false, + 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", DISABLED, "Enable option to launch search results using the new view container transitions"); public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag( - 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true, + 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED, "Enable option to show keyboard when going to all-apps"); public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973, - "USE_LOCAL_ICON_OVERRIDES", true, + "USE_LOCAL_ICON_OVERRIDES", ENABLED, "Use inbuilt monochrome icons if app doesn't provide one"); public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476, - "ENABLE_DISMISS_PREDICTION_UNDO", false, + "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED, "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"); public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(270395008, - "ENABLE_CACHED_WIDGET", true, + "ENABLE_CACHED_WIDGET", ENABLED, "Show previously cached widgets as opposed to deferred widget where available"); public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010, - "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", false, + "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED, "Use local overrides for search request timeout"); public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171, - "CONTINUOUS_VIEW_TREE_CAPTURE", true, "Capture View tree every frame"); + "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame"); - public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag( - 270395140, "SECONDARY_DRAG_N_DROP_TO_PIN", false, + public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140, + "SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED, "Enable dragging and dropping to pin apps within secondary display"); public static final BooleanFlag FOLDABLE_WORKSPACE_REORDER = getDebugFlag(270395070, - "FOLDABLE_WORKSPACE_REORDER", false, + "FOLDABLE_WORKSPACE_REORDER", DISABLED, "In foldables, when reordering the icons and widgets, is now going to use both sides"); public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073, - "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", false, + "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", DISABLED, "Allow bottom sheet depth to be smaller than 1 for multi-display devices."); - public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag( - 270395177, "SCROLL_TOP_TO_RESET", true, + public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(270395177, + "SCROLL_TOP_TO_RESET", ENABLED, "Bring up IME and focus on input when scroll to top if 'Always show keyboard'" + " is enabled or in prefix state"); public static final BooleanFlag ENABLE_MATERIAL_U_POPUP = getDebugFlag(270395516, - "ENABLE_MATERIAL_U_POPUP", true, "Switch popup UX to use material U"); + "ENABLE_MATERIAL_U_POPUP", ENABLED, "Switch popup UX to use material U"); public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269, - "ENABLE_SEARCH_UNINSTALLED_APPS", false, "Search uninstalled app results."); + "ENABLE_SEARCH_UNINSTALLED_APPS", DISABLED, "Search uninstalled app results."); public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(270395183, - "SHOW_HOME_GARDENING", false, - "Show the new home gardening mode"); + "SHOW_HOME_GARDENING", DISABLED, "Show the new home gardening mode"); public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(270395133, - "HOME_GARDENING_WORKSPACE_BUTTONS", false, + "HOME_GARDENING_WORKSPACE_BUTTONS", DISABLED, "Change workspace edit buttons to reflect home gardening"); public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getReleaseFlag(270395134, - "ENABLE_DOWNLOAD_APP_UX_V2", true, "Updates the download app UX" + "ENABLE_DOWNLOAD_APP_UX_V2", ENABLED, "Updates the download app UX" + " to have better visuals"); public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(270395186, - "ENABLE_DOWNLOAD_APP_UX_V3", false, "Updates the download app UX" + "ENABLE_DOWNLOAD_APP_UX_V3", DISABLED, "Updates the download app UX" + " to have better visuals, improve contrast, and color"); public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag(270395077, - "FORCE_PERSISTENT_TASKBAR", false, "Forces taskbar to be persistent, even in gesture" + "FORCE_PERSISTENT_TASKBAR", DISABLED, "Forces taskbar to be persistent, even in gesture" + " nav mode and when transient taskbar is enabled."); public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274, - "FOLDABLE_SINGLE_PAGE", true, - "Use a single page for the workspace"); + "FOLDABLE_SINGLE_PAGE", ENABLED, "Use a single page for the workspace"); public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798, - "ENABLE_TRANSIENT_TASKBAR", true, "Enables transient taskbar."); + "ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar."); public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401, - "ENABLE_TRACKPAD_GESTURE", true, "Enables trackpad gesture."); + "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture."); public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143, - "ENABLE_ICON_IN_TEXT_HEADER", false, "Show icon in textheader"); + "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader"); public static final BooleanFlag ENABLE_APP_ICON_FOR_INLINE_SHORTCUTS = getDebugFlag(270395087, - "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", false, "Show app icon for inline shortcut"); + "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut"); public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(270395278, - "SHOW_DOT_PAGINATION", true, "Enable showing dot pagination in workspace"); + "SHOW_DOT_PAGINATION", ENABLED, "Enable showing dot pagination in workspace"); public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(270395809, - "LARGE_SCREEN_WIDGET_PICKER", true, "Enable new widget picker that takes " + "LARGE_SCREEN_WIDGET_PICKER", ENABLED, "Enable new widget picker that takes " + "advantage of large screen format"); public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257, - "ENABLE_NEW_GESTURE_NAV_TUTORIAL", true, + "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED, "Enable the redesigned gesture navigation tutorial"); public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(270395567, - "ENABLE_LAUNCH_FROM_STAGED_APP", true, - "Enable the ability to tap a staged app during split select to launch it in full screen" - ); + "ENABLE_LAUNCH_FROM_STAGED_APP", ENABLED, + "Enable the ability to tap a staged app during split select to launch it in full " + + "screen"); public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358, - "ENABLE_PREMIUM_HAPTICS_ALL_APPS", false, + "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED, "Enables haptics opening/closing All apps"); public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(270396209, - "ENABLE_FORCED_MONO_ICON", false, - "Enable the ability to generate monochromatic icons, if it is not provided by the app" - ); + "ENABLE_FORCED_MONO_ICON", DISABLED, + "Enable the ability to generate monochromatic icons, if it is not provided by the app"); public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(270396268, - "ENABLE_TASKBAR_EDU_TOOLTIP", true, + "ENABLE_TASKBAR_EDU_TOOLTIP", ENABLED, "Enable the tooltip version of the Taskbar education flow."); public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680, - "ENABLE_MULTI_INSTANCE", false, + "ENABLE_MULTI_INSTANCE", DISABLED, "Enables creation and filtering of multiple task instances in overview"); public static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583, - "ENABLE_TASKBAR_PINNING", false, + "ENABLE_TASKBAR_PINNING", DISABLED, "Enables taskbar pinning to allow user to switch between transient and persistent " + "taskbar flavors"); public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424, - "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", false, "load the current workspace screen " - + "visible to the user before the rest rather than loading all of them at once." - ); + "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED, + "load the current workspace screen visible to the user before the rest rather than " + + "loading all of them at once."); public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206, - "ENABLE_GRID_ONLY_OVERVIEW", false, + "ENABLE_GRID_ONLY_OVERVIEW", DISABLED, "Enable a grid-only overview without a focused task."); public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag(270397209, - "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", true, + "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", ENABLED, "Enables receiving unfold animation events from sysui instead of calculating " + "them in launcher process using hinge sensor values."); public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844, - "ENABLE_KEYBOARD_QUICK_SWITCH", true, - "Enables keyboard quick switching"); + "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching"); public static final BooleanFlag ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER = getDebugFlag(266177840, - "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", false, + "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", DISABLED, "Removes clone apps from the work profile tab."); public static final BooleanFlag ENABLE_APP_PAIRS = getDebugFlag(274189428, - "ENABLE_APP_PAIRS", false, + "ENABLE_APP_PAIRS", DISABLED, "Enables the ability to create and save app pairs on the Home screen for easy" + " split screen launching."); @@ -437,4 +428,13 @@ public final class FeatureFlags { return sIntReader.applyAsInt(this); } } + + /** + * Enabled state for a flag + */ + public enum FlagState { + ENABLED, + DISABLED, + TEAMFOOD // Enabled in team food + } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java index 4463adcf06..eb0494e2c2 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java @@ -16,7 +16,10 @@ package com.android.launcher3.uioverrides.flags; +import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED; + import com.android.launcher3.config.FeatureFlags.BooleanFlag; +import com.android.launcher3.config.FeatureFlags.FlagState; import com.android.launcher3.config.FeatureFlags.IntFlag; import java.io.PrintWriter; @@ -31,16 +34,16 @@ public class FlagsFactory { * Creates a new debug flag */ public static BooleanFlag getDebugFlag( - int bugId, String key, boolean defaultValue, String description) { - return new BooleanFlag(defaultValue); + int bugId, String key, FlagState flagState, String description) { + return new BooleanFlag(flagState == ENABLED); } /** * Creates a new debug flag */ public static BooleanFlag getReleaseFlag( - int bugId, String key, boolean defaultValueInCode, String description) { - return new BooleanFlag(defaultValueInCode); + int bugId, String key, FlagState flagState, String description) { + return new BooleanFlag(flagState == ENABLED); } /**