Snap for 12140224 from acc4a81a97 to 24Q4-release

Change-Id: I7eb895e43bb3a266e4d3d4fc54dfef6a22b6deca
This commit is contained in:
Android Build Coastguard Worker
2024-07-25 23:21:26 +00:00
15 changed files with 286 additions and 24 deletions
+13
View File
@@ -316,3 +316,16 @@ flag {
description: "Archived apps will use new icon in app title"
bug: "350758155"
}
flag {
name: "enable_multi_instance_menu_taskbar"
namespace: "launcher"
description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
bug: "355237285"
}
flag {
name: "navigate_to_child_preference"
namespace: "launcher"
description: "Settings screen supports navigating to child preference if the key is not on the screen"
bug: "293390881"
}
@@ -290,6 +290,9 @@ public class PredictionRowView<T extends Context & ActivityContext>
writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled);
writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused);
writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow);
writer.println(prefix + "\tmPredictedApps: " + mPredictedApps);
writer.println(prefix + "\tmPredictedApps: " + mPredictedApps.size());
for (WorkspaceItemInfo info : mPredictedApps) {
writer.println(prefix + "\t\t" + info);
}
}
}
@@ -536,6 +536,9 @@ public class HotseatPredictionController implements DragController.DragListener,
writer.println(prefix + "HotseatPredictionController");
writer.println(prefix + "\tFlags: " + getStateString(mPauseFlags));
writer.println(prefix + "\tmHotSeatItemsCount: " + mHotSeatItemsCount);
writer.println(prefix + "\tmPredictedItems: " + mPredictedItems);
writer.println(prefix + "\tmPredictedItems: " + mPredictedItems.size());
for (ItemInfo info : mPredictedItems) {
writer.println(prefix + "\t\t" + info);
}
}
}
@@ -272,6 +272,10 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
* app launch animation.
*/
public void setIgnoreInAppFlagForSync(boolean enabled) {
if (mControllers == null) {
// This method can be called before init() is called.
return;
}
mControllers.taskbarStashController.updateStateForFlag(FLAG_IGNORE_IN_APP, enabled);
}
@@ -31,4 +31,7 @@ class RecentsViewData {
// The settled set of visible taskIds that is updated after RecentsView scroll settles.
val settledFullyVisibleTaskIds = MutableStateFlow(emptySet<Int>())
// Color tint on foreground scrim
val tintAmount = MutableStateFlow(0f)
}
@@ -45,4 +45,8 @@ class RecentsViewModel(
fun setOverlayEnabled(isOverlayEnabled: Boolean) {
recentsViewData.overlayEnabled.value = isOverlayEnabled
}
fun setTintAmount(tintAmount: Float) {
recentsViewData.tintAmount.value = tintAmount
}
}
@@ -98,10 +98,7 @@ class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
}
.launchIn(viewAttachedScope)
viewModel.dimProgress
.onEach { dimProgress ->
// TODO(b/348195366) Add fade in/out for scrim
scrimView.alpha = dimProgress * MAX_SCRIM_ALPHA
}
.onEach { dimProgress -> scrimView.alpha = dimProgress }
.launchIn(viewAttachedScope)
viewModel.cornerRadiusProgress.onEach { invalidateOutline() }.launchIn(viewAttachedScope)
viewModel.inheritedScale
@@ -176,8 +173,4 @@ class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
overviewCornerRadius,
fullscreenCornerRadius
) / inheritedScale
private companion object {
const val MAX_SCRIM_ALPHA = 0.4f
}
}
@@ -30,6 +30,7 @@ import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.systemui.shared.recents.model.Task
import kotlin.math.max
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -63,7 +64,12 @@ class TaskThumbnailViewModel(
combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
recentsScale * taskScale
}
val dimProgress: Flow<Float> = taskContainerData.taskMenuOpenProgress
val dimProgress: Flow<Float> =
combine(taskContainerData.taskMenuOpenProgress, recentsViewData.tintAmount) {
taskMenuOpenProgress,
tintAmount ->
max(taskMenuOpenProgress * MAX_SCRIM_ALPHA, tintAmount)
}
val uiState: Flow<TaskThumbnailUiState> =
task
.flatMapLatest { taskFlow ->
@@ -110,4 +116,8 @@ class TaskThumbnailViewModel(
}
@ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
private companion object {
const val MAX_SCRIM_ALPHA = 0.4f
}
}
@@ -6116,7 +6116,6 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
* tasks to be dimmed while other elements in the recents view are left alone.
*/
public void showForegroundScrim(boolean show) {
// TODO(b/349601769) Add scrim response into new TTV - this is called from overlay
if (!show && mColorTint == 0) {
if (mTintingAnimator != null) {
mTintingAnimator.cancel();
@@ -6135,6 +6134,10 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
private void setColorTint(float tintAmount) {
mColorTint = tintAmount;
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.setTintAmount(tintAmount);
}
for (int i = 0; i < getTaskViewCount(); i++) {
requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
}
@@ -212,6 +212,27 @@ class TaskThumbnailViewModelTest {
.isEqualTo(MATRIX)
}
@Test
fun getForegroundScrimDimProgress_returnsForegroundMaxScrim() = runTest {
recentsViewData.tintAmount.value = 0.32f
taskContainerData.taskMenuOpenProgress.value = 0f
assertThat(systemUnderTest.dimProgress.first()).isEqualTo(0.32f)
}
@Test
fun getTaskMenuScrimDimProgress_returnsTaskMenuScrim() = runTest {
recentsViewData.tintAmount.value = 0f
taskContainerData.taskMenuOpenProgress.value = 1f
assertThat(systemUnderTest.dimProgress.first()).isEqualTo(0.4f)
}
@Test
fun getForegroundScrimDimProgress_returnsNoScrim() = runTest {
recentsViewData.tintAmount.value = 0f
taskContainerData.taskMenuOpenProgress.value = 0f
assertThat(systemUnderTest.dimProgress.first()).isEqualTo(0f)
}
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
colorBackground = Color.argb(taskId, taskId, taskId, taskId)
@@ -0,0 +1,65 @@
/*
* 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.quickstep.util
import com.android.launcher3.BuildConfig
import com.android.launcher3.util.SafeCloseable
import com.android.quickstep.DeviceConfigWrapper.Companion.configHelper
import com.android.quickstep.util.DeviceConfigHelper.Companion.prefs
import java.util.concurrent.CountDownLatch
import java.util.function.BooleanSupplier
import org.junit.Assert
import org.junit.Assume
/** Helper methods for testing */
object TestExtensions {
@JvmStatic
fun overrideNavConfigFlag(
key: String,
value: Boolean,
targetValue: BooleanSupplier
): AutoCloseable {
Assume.assumeTrue(BuildConfig.IS_DEBUG_DEVICE)
if (targetValue.asBoolean == value) {
return AutoCloseable {}
}
navConfigEditWatcher().let {
prefs.edit().putBoolean(key, value).commit()
it.close()
}
Assert.assertEquals(value, targetValue.asBoolean)
val watcher = navConfigEditWatcher()
return AutoCloseable {
prefs.edit().remove(key).commit()
watcher.close()
}
}
private fun navConfigEditWatcher(): SafeCloseable {
val wait = CountDownLatch(1)
val listener = Runnable { wait.countDown() }
configHelper.addChangeListener(listener)
return SafeCloseable {
wait.await()
configHelper.removeChangeListener(listener)
}
}
}
@@ -21,6 +21,7 @@ import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.VisibleForTesting;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -53,13 +54,21 @@ public class FloatingMaskView extends ConstraintLayout {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
AllAppsRecyclerView allAppsContainerView =
mActivityContext.getAppsView().getActiveRecyclerView();
setParameters((ViewGroup.MarginLayoutParams) getLayoutParams(),
mActivityContext.getAppsView().getActiveRecyclerView());
}
@VisibleForTesting
void setParameters(ViewGroup.MarginLayoutParams lp, AllAppsRecyclerView recyclerView) {
if (lp != null) {
lp.rightMargin = allAppsContainerView.getPaddingRight();
lp.leftMargin = allAppsContainerView.getPaddingLeft();
mBottomBox.setMinimumHeight(allAppsContainerView.getPaddingBottom());
lp.rightMargin = recyclerView.getPaddingRight();
lp.leftMargin = recyclerView.getPaddingLeft();
getBottomBox().setMinimumHeight(recyclerView.getPaddingBottom());
}
}
@VisibleForTesting
ImageView getBottomBox() {
return mBottomBox;
}
}
@@ -403,6 +403,7 @@ public class PrivateProfileManager extends UserProfileManager {
mLockText.setHorizontallyScrolling(false);
mPrivateSpaceSettingsButton.setVisibility(
isPrivateSpaceSettingsAvailable() ? VISIBLE : GONE);
mPrivateSpaceSettingsButton.setClickable(isPrivateSpaceSettingsAvailable());
}
lockPill.setVisibility(VISIBLE);
lockPill.setOnClickListener(view -> lockingAction(/* lock */ true));
@@ -425,6 +426,7 @@ public class PrivateProfileManager extends UserProfileManager {
lockPill.setContentDescription(mLockedStateContentDesc);
mPrivateSpaceSettingsButton.setVisibility(GONE);
mPrivateSpaceSettingsButton.setClickable(false);
transitionView.setVisibility(GONE);
}
case STATE_TRANSITION -> {
@@ -660,10 +662,7 @@ public class PrivateProfileManager extends UserProfileManager {
return;
}
attachFloatingMaskView(expand);
PropertySetter headerSetter = new AnimatedPropertySetter();
headerSetter.add(updateSettingsGearAlpha(expand));
headerSetter.add(updateLockTextAlpha(expand));
AnimatorSet animatorSet = headerSetter.buildAnim();
AnimatorSet animatorSet = new AnimatedPropertySetter().buildAnim();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -708,12 +707,16 @@ public class PrivateProfileManager extends UserProfileManager {
}
}));
if (expand) {
animatorSet.playTogether(animateAlphaOfIcons(true),
animatorSet.playTogether(updateSettingsGearAlpha(true),
updateLockTextAlpha(true),
animateAlphaOfIcons(true),
animatePillTransition(true),
translateFloatingMaskView(false));
} else {
AnimatorSet parallelSet = new AnimatorSet();
parallelSet.playTogether(animateAlphaOfIcons(false),
parallelSet.playTogether(updateSettingsGearAlpha(false),
updateLockTextAlpha(false),
animateAlphaOfIcons(false),
animatePillTransition(false));
if (isPrivateSpaceHidden()) {
animatorSet.playSequentially(parallelSet,
@@ -794,6 +797,14 @@ public class PrivateProfileManager extends UserProfileManager {
@Override
public void onAnimationStart(Animator animator) {
mPrivateSpaceSettingsButton.setVisibility(VISIBLE);
mPrivateSpaceSettingsButton.setClickable(false);
}
@Override
public void onAnimationEnd(Animator animator) {
if (expand) {
mPrivateSpaceSettingsButton.setClickable(true);
}
}
});
return settingsAlphaAnim;
@@ -44,11 +44,13 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback;
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceGroup.PreferencePositionCallback;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BuildConfig;
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherFiles;
import com.android.launcher3.R;
import com.android.launcher3.states.RotationHelper;
@@ -165,6 +167,7 @@ public class SettingsActivity extends FragmentActivity
private boolean mRestartOnResume = false;
private String mHighLightKey;
private boolean mPreferenceHighlighted = false;
@Override
@@ -198,11 +201,62 @@ public class SettingsActivity extends FragmentActivity
}
}
// If the target preference is not in the current preference screen, find the parent
// preference screen that contains the target preference and set it as the preference
// screen.
if (Flags.navigateToChildPreference()
&& mHighLightKey != null
&& !isKeyInPreferenceGroup(mHighLightKey, screen)) {
final PreferenceScreen parentPreferenceScreen =
findParentPreference(screen, mHighLightKey);
if (parentPreferenceScreen != null && getActivity() != null) {
if (!TextUtils.isEmpty(parentPreferenceScreen.getTitle())) {
getActivity().setTitle(parentPreferenceScreen.getTitle());
}
setPreferenceScreen(parentPreferenceScreen);
return;
}
}
if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) {
getActivity().setTitle(getPreferenceScreen().getTitle());
}
}
private boolean isKeyInPreferenceGroup(String targetKey, PreferenceGroup parent) {
for (int i = 0; i < parent.getPreferenceCount(); i++) {
Preference pref = parent.getPreference(i);
if (pref.getKey() != null && pref.getKey().equals(targetKey)) {
return true;
}
}
return false;
}
/**
* Finds the parent preference screen for the given target key.
*
* @param parent the parent preference screen
* @param targetKey the key of the preference to find
* @return the parent preference screen that contains the target preference
*/
@Nullable
private PreferenceScreen findParentPreference(PreferenceScreen parent, String targetKey) {
for (int i = 0; i < parent.getPreferenceCount(); i++) {
Preference pref = parent.getPreference(i);
if (pref instanceof PreferenceScreen) {
PreferenceScreen foundKey = findParentPreference((PreferenceScreen) pref,
targetKey);
if (foundKey != null) {
return foundKey;
}
} else if (pref.getKey() != null && pref.getKey().equals(targetKey)) {
return parent;
}
}
return null;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -0,0 +1,66 @@
/*
* 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.launcher3.allapps
import android.content.Context
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.ImageView
import androidx.test.core.app.ApplicationProvider
import com.android.launcher3.util.ActivityContextWrapper
import com.google.common.truth.Truth
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
class FloatingMaskViewTest {
@Mock
private val mockAllAppsRecyclerView: AllAppsRecyclerView? = null
@Mock
private val mockBottomBox: ImageView? = null
private var mVut: FloatingMaskView? = null
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val context: Context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
mVut = FloatingMaskView(context)
mVut!!.layoutParams = MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
}
@Test
fun setParameters_paramsMarginEqualRecyclerViewPadding() {
val floatingMaskView = Mockito.spy(mVut)
Mockito.`when`(mockAllAppsRecyclerView!!.paddingLeft).thenReturn(PADDING_PX)
Mockito.`when`(mockAllAppsRecyclerView.paddingRight).thenReturn(PADDING_PX)
Mockito.`when`(mockAllAppsRecyclerView.paddingBottom).thenReturn(PADDING_PX)
Mockito.`when`(floatingMaskView!!.bottomBox).thenReturn(mockBottomBox)
val lp = floatingMaskView.layoutParams as MarginLayoutParams
floatingMaskView.setParameters(lp, mockAllAppsRecyclerView)
Truth.assertThat(lp.leftMargin).isEqualTo(PADDING_PX)
Truth.assertThat(lp.rightMargin).isEqualTo(PADDING_PX)
Mockito.verify(mockBottomBox)?.minimumHeight = PADDING_PX
}
companion object {
private const val PADDING_PX = 15
}
}