Merge changes I7c303e66,Idc03b9d3 into main

* changes:
  Add floatingMaskView when animating to mimic bottom container.
  Add private_space_floating_mask_view flag.
This commit is contained in:
Brandon Dayauon
2024-05-14 23:15:40 +00:00
committed by Android (Google) Code Review
7 changed files with 264 additions and 6 deletions

View File

@@ -42,3 +42,11 @@ flag {
description: "This flag disables drag and drop for Private Space Items."
bug: "289223923"
}
flag {
name: "private_space_floating_mask_view"
namespace: "launcher_search"
description: "This flag enables the floating mask view as part of the Private Space animation. "
bug: "339850589"
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<vector
android:viewportWidth="28"
android:viewportHeight="28"
android:width="@dimen/ps_floating_mask_corner_radius"
android:height="@dimen/ps_floating_mask_corner_radius">
<path
android:pathData="M0 28H28C24.3228 28 20.6821 27.2759 17.2847 25.8687C13.8877 24.4614 10.8013 22.3989 8.20117 19.7988C5.60107 17.1987 3.53857 14.1123 2.13135 10.7153C0.724121 7.31787 0 3.67725 0 0V28Z"
android:fillType="evenOdd"
android:fillColor="?attr/allAppsScrimColor" />
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<vector
android:viewportWidth="28"
android:viewportHeight="28"
android:width="@dimen/ps_floating_mask_corner_radius"
android:height="@dimen/ps_floating_mask_corner_radius">
<path
android:pathData="M28 28V0C28 3.67725 27.2759 7.31787 25.8687 10.7153C24.4614 14.1123 22.3989 17.1987 19.7988 19.7988C17.1987 22.3989 14.1123 24.4614 10.7153 25.8687C7.31787 27.2759 3.67725 28 0 28H28Z"
android:fillType="evenOdd"
android:fillColor="?attr/allAppsScrimColor" />
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->
<com.android.launcher3.allapps.FloatingMaskView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/ps_floating_mask_end_padding"
android:layout_marginRight="@dimen/ps_floating_mask_end_padding"
android:importantForAccessibility="noHideDescendants"
android:orientation="horizontal">
<ImageView
android:id="@+id/left_corner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
android:importantForAccessibility="no"
android:background="@drawable/bg_ps_mask_left_corner"/>
<ImageView
android:id="@+id/right_corner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
android:importantForAccessibility="no"
android:background="@drawable/bg_ps_mask_right_corner"/>
<ImageView
android:id="@+id/bottom_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/left_corner"
app:layout_constraintEnd_toEndOf="@id/right_corner"
app:layout_constraintTop_toBottomOf="@id/left_corner"
android:importantForAccessibility="no"
android:background="?attr/allAppsScrimColor"/>
</com.android.launcher3.allapps.FloatingMaskView>

View File

@@ -536,6 +536,8 @@
<dimen name="ps_lock_icon_text_margin_start_expanded">8dp</dimen>
<dimen name="ps_lock_icon_text_margin_end_expanded">6dp</dimen>
<dimen name="ps_lock_button_background_padding">10dp</dimen>
<dimen name="ps_floating_mask_corner_radius">28dp</dimen>
<dimen name="ps_floating_mask_end_padding">16dp</dimen>
<!-- WindowManagerProxy -->
<dimen name="max_width_and_height_of_small_display_cutout">136px</dimen>

View File

@@ -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.launcher3.allapps;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
import com.android.launcher3.views.ActivityContext;
public class FloatingMaskView extends ConstraintLayout {
private final ActivityContext mActivityContext;
private ImageView mBottomBox;
public FloatingMaskView(Context context) {
this(context, null, 0);
}
public FloatingMaskView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FloatingMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mActivityContext = ActivityContext.lookupContext(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mBottomBox = findViewById(R.id.bottom_box);
}
@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();
if (lp != null) {
lp.rightMargin = allAppsContainerView.getPaddingRight();
lp.leftMargin = allAppsContainerView.getPaddingLeft();
mBottomBox.setMinimumHeight(allAppsContainerView.getPaddingBottom());
}
}
}

View File

@@ -60,6 +60,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
@@ -96,14 +97,17 @@ public class PrivateProfileManager extends UserProfileManager {
private static final int TEXT_UNLOCK_OPACITY_DURATION = 300;
private static final int TEXT_LOCK_OPACITY_DURATION = 50;
private static final int APP_OPACITY_DURATION = 400;
private static final int MASK_VIEW_DURATION = 200;
private static final int APP_OPACITY_DELAY = 400;
private static final int SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY = 400;
private static final int SETTINGS_OPACITY_DELAY = 400;
private static final int LOCK_TEXT_OPACITY_DELAY = 500;
private static final int MASK_VIEW_DELAY = 400;
private static final int NO_DELAY = 0;
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private final int mPsHeaderHeight;
private final int mFloatingMaskViewCornerRadius;
private final RecyclerView.OnScrollListener mOnIdleScrollListener =
new RecyclerView.OnScrollListener() {
@Override
@@ -123,6 +127,7 @@ public class PrivateProfileManager extends UserProfileManager {
private Runnable mOnPSHeaderAdded;
@Nullable
private RelativeLayout mPSHeader;
private ConstraintLayout mFloatingMaskView;
private final String mLockedStateContentDesc;
private final String mUnLockedStateContentDesc;
@@ -142,6 +147,8 @@ public class PrivateProfileManager extends UserProfileManager {
.getString(R.string.ps_container_lock_button_content_description);
mUnLockedStateContentDesc = mAllApps.getContext()
.getString(R.string.ps_container_unlock_button_content_description);
mFloatingMaskViewCornerRadius = mAllApps.getContext().getResources().getDimensionPixelSize(
R.dimen.ps_floating_mask_corner_radius);
}
/** Adds Private Space Header to the layout. */
@@ -219,6 +226,7 @@ public class PrivateProfileManager extends UserProfileManager {
.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
setCurrentState(updatedState);
mFloatingMaskView = null;
if (mPSHeader != null) {
mPSHeader.setAlpha(1);
}
@@ -494,12 +502,15 @@ public class PrivateProfileManager extends UserProfileManager {
RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
if (layoutManager != null) {
startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
currentItem.decorationInfo = null;
// Preserve decorator if floating mask view exists.
if (mFloatingMaskView == null) {
currentItem.decorationInfo = null;
}
}
break;
}
// Make the private space apps gone to "collapse".
if (isPrivateSpaceItem(currentItem)) {
if (mFloatingMaskView == null && isPrivateSpaceItem(currentItem)) {
RecyclerView.ViewHolder viewHolder =
allAppsRecyclerView.findViewHolderForAdapterPosition(i);
if (viewHolder != null) {
@@ -637,6 +648,7 @@ public class PrivateProfileManager extends UserProfileManager {
setAnimationRunning(false);
return;
}
attachFloatingMaskView(expand);
ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
if (settingsAndLockGroup.getLayoutTransition() == null) {
// Set a new transition if the current ViewGroup does not already contain one as each
@@ -662,6 +674,11 @@ public class PrivateProfileManager extends UserProfileManager {
mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
setAnimationRunning(true);
}
@Override
public void onAnimationEnd(Animator animation) {
detachFloatingMaskView();
}
});
animatorSet.addListener(forEndCallback(() -> {
setAnimationRunning(false);
@@ -681,13 +698,17 @@ public class PrivateProfileManager extends UserProfileManager {
}
}));
if (expand) {
animatorSet.playTogether(animateAlphaOfIcons(true));
animatorSet.playTogether(animateAlphaOfIcons(true),
translateFloatingMaskView(false));
} else {
if (isPrivateSpaceHidden()) {
animatorSet.playSequentially(animateAlphaOfIcons(false),
animateCollapseAnimation(), fadeOutHeaderAlpha());
animatorSet.playSequentially(translateFloatingMaskView(false),
animateAlphaOfIcons(false),
animateCollapseAnimation(),
fadeOutHeaderAlpha());
} else {
animatorSet.playSequentially(animateAlphaOfIcons(false),
animatorSet.playSequentially(translateFloatingMaskView(true),
animateAlphaOfIcons(false),
animateCollapseAnimation());
}
}
@@ -715,6 +736,27 @@ public class PrivateProfileManager extends UserProfileManager {
return alphaAnim;
}
/** Fades out the private space container. */
private ValueAnimator translateFloatingMaskView(boolean animateIn) {
if (!Flags.privateSpaceFloatingMaskView() || mFloatingMaskView == null) {
return new ValueAnimator();
}
// Translate base on the height amount. Translates out on expand and in on collapse.
float floatingMaskViewHeight = getFloatingMaskViewHeight();
float from = animateIn ? floatingMaskViewHeight : 0;
float to = animateIn ? 0 : floatingMaskViewHeight;
ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
alphaAnim.setDuration(MASK_VIEW_DURATION);
alphaAnim.setStartDelay(MASK_VIEW_DELAY);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mFloatingMaskView.setTranslationY((float) valueAnimator.getAnimatedValue());
}
});
return alphaAnim;
}
/** Animates the layout changes when the text of the button becomes visible/gone. */
private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
LayoutTransition settingsAndLockTransition = new LayoutTransition();
@@ -806,6 +848,28 @@ public class PrivateProfileManager extends UserProfileManager {
});
}
private void attachFloatingMaskView(boolean expand) {
if (!Flags.privateSpaceFloatingMaskView()) {
return;
}
mFloatingMaskView = (FloatingMaskView) mAllApps.getLayoutInflater().inflate(
R.layout.private_space_mask_view, mAllApps, false);
mAllApps.addView(mFloatingMaskView);
// Translate off the screen first if its collapsing so this header view isn't visible to
// user when animation starts.
if (!expand) {
mFloatingMaskView.setTranslationY(getFloatingMaskViewHeight());
}
mFloatingMaskView.setVisibility(VISIBLE);
}
private void detachFloatingMaskView() {
if (mFloatingMaskView != null) {
mAllApps.removeView(mFloatingMaskView);
}
mFloatingMaskView = null;
}
/** Starts the smooth scroll with the provided smoothScroller and add idle listener. */
private void startAnimationScroll(AllAppsRecyclerView allAppsRecyclerView,
RecyclerView.LayoutManager layoutManager, RecyclerView.SmoothScroller smoothScroller) {
@@ -815,6 +879,10 @@ public class PrivateProfileManager extends UserProfileManager {
allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
}
private float getFloatingMaskViewHeight() {
return mFloatingMaskViewCornerRadius + getMainRecyclerView().getPaddingBottom();
}
AllAppsRecyclerView getMainRecyclerView() {
return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
}