Merge "Refactor FolderInsetAnimationCallback to be used with any view" into sc-dev

This commit is contained in:
Samuel Fufa 2021-06-17 18:48:49 +00:00 committed by Android (Google) Code Review
commit efa5df380c
12 changed files with 170 additions and 106 deletions

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.
@ -16,10 +15,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/textColorHint" >
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/textColorHint">
<path
android:pathData="M22 7.95c.05-1.11-.84-2-1.95-1.95H16V3.95c0-1.11-.84-2-1.95-1.95h-4C8.94 1.95 8 2.84 8 3.95v.32l14 14V7.95zM14 6h-4V4h4v2zm7.54 14.28l-7.56-7.56v.01l-1.7-1.7h.01L7.21 5.95 3.25 1.99 1.99 3.27 4.69 6h-.64c-1.11 0-1.99.86-1.99 1.97l-.01 11.02c0 1.11.89 2.01 2 2.01h15.64l2.05 2.02L23 21.75l-1.46-1.47z"
android:fillColor="@android:color/white"/>
android:fillColor="@android:color/white"
android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z" />
</vector>

View File

@ -18,10 +18,10 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/work_edu_card_margin" />
<corners android:radius="@dimen/rounded_button_radius" />
<stroke android:width="1dp" android:color="?androidprv:attr/colorAccentPrimaryVariant" />
<padding
android:left="@dimen/work_fab_radius"
android:right="@dimen/work_fab_radius" />
android:left="@dimen/rounded_button_padding"
android:right="@dimen/rounded_button_padding" />
</shape>

View File

@ -47,7 +47,8 @@
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_profile_edu_accept"
android:textAlignment="center"
android:background="@drawable/work_card_btn"
android:background="@drawable/rounded_action_button"
android:textSize="14sp" />
</LinearLayout>
</com.android.launcher3.allapps.WorkEduCard>

View File

@ -48,6 +48,6 @@
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_apps_enable_btn_text"
android:textAlignment="center"
android:background="@drawable/work_card_btn"
android:background="@drawable/rounded_action_button"
android:textSize="14sp" />
</com.android.launcher3.allapps.WorkPausedCard>

View File

@ -25,7 +25,6 @@
android:background="@drawable/work_apps_toggle_background"
android:drawablePadding="16dp"
android:drawableStart="@drawable/ic_corp_off"
android:elevation="10dp"
android:layout_marginBottom="@dimen/work_fab_margin"
android:layout_marginEnd="@dimen/work_fab_margin"
android:text="@string/work_apps_pause_btn_text" />

View File

@ -120,11 +120,16 @@
<!-- Floating action button inside work tab to toggle work profile -->
<dimen name="work_fab_height">48dp</dimen>
<dimen name="work_fab_radius">24dp</dimen>
<dimen name="work_fab_margin">18dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_profile_footer_text_size">16sp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
<!-- rounded button shown inside card views, and snack bars -->
<dimen name="rounded_button_height">32dp</dimen>
<dimen name="rounded_button_radius">16dp</dimen>
<dimen name="rounded_button_padding">8dp</dimen>
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>

View File

@ -131,7 +131,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
private ScrimView mScrimView;
private int mHeaderColor;
public AllAppsContainerView(Context context) {
this(context, null);
}
@ -571,6 +570,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
}
public int getCurrentPage() {
return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
}
/**
* Handles selection on focused view and returns success
*/

View File

@ -19,6 +19,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.os.Process;
@ -27,13 +28,16 @@ import android.os.UserManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.Button;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
import com.android.launcher3.pm.UserCache;
/**
@ -44,6 +48,10 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
private Rect mInsets = new Rect();
private boolean mWorkEnabled;
@Nullable
private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
public WorkModeSwitch(Context context) {
this(context, null, 0);
}
@ -60,6 +68,10 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
protected void onFinishInflate() {
super.onFinishInflate();
setOnClickListener(this);
if (Utilities.ATLEAST_R) {
mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
}
@Override
@ -121,4 +133,16 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
}
return showConfirm;
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Utilities.ATLEAST_R) {
setTranslationY(0);
if (insets.isVisible(WindowInsets.Type.ime())) {
Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
setTranslationY(mInsets.bottom - keyboardInsets.bottom);
}
}
return insets;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2021 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.anim;
import android.os.Build;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import androidx.annotation.RequiresApi;
import com.android.launcher3.Utilities;
import java.util.List;
/**
* Callback that animates views above the IME
*/
@RequiresApi(api = Build.VERSION_CODES.R)
public class KeyboardInsetAnimationCallback extends WindowInsetsAnimation.Callback {
private final View mView;
private float mInitialTranslation;
private float mTerminalTranslation;
public KeyboardInsetAnimationCallback(View view) {
super(DISPATCH_MODE_STOP);
mView = view;
}
@Override
public void onPrepare(WindowInsetsAnimation animation) {
mInitialTranslation = mView.getTranslationY();
}
@Override
public WindowInsets onProgress(WindowInsets windowInsets, List<WindowInsetsAnimation> list) {
if (list.size() == 0) {
mView.setTranslationY(mInitialTranslation);
return windowInsets;
}
float progress = list.get(0).getInterpolatedFraction();
mView.setTranslationY(
Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation));
return windowInsets;
}
@Override
public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
WindowInsetsAnimation.Bounds bounds) {
mTerminalTranslation = mView.getTranslationY();
mView.setTranslationY(mInitialTranslation);
return super.onStart(animation, bounds);
}
}

View File

@ -99,6 +99,9 @@ public final class FeatureFlags {
public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(
"IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps");
public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
"ENABLE_PEOPLE_TILE_PREVIEW", false,
"Experimental: Shows conversation shortcuts on home screen as search results");

View File

@ -17,7 +17,6 @@
package com.android.launcher3.folder;
import static android.text.TextUtils.isEmpty;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
@ -39,7 +38,6 @@ import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.text.InputType;
import android.text.Selection;
import android.text.TextUtils;
@ -54,15 +52,12 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.res.ResourcesCompat;
import com.android.launcher3.AbstractFloatingView;
@ -83,6 +78,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
@ -164,9 +160,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
private final Alarm mReorderAlarm = new Alarm();
private final Alarm mOnExitAlarm = new Alarm();
private final Alarm mOnScrollHintAlarm = new Alarm();
@Thunk final Alarm mScrollPauseAlarm = new Alarm();
final Alarm mScrollPauseAlarm = new Alarm();
@Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
private AnimatorSet mCurrentAnimator;
private boolean mIsAnimatingClosed = false;
@ -182,9 +178,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
private CharSequence mFromTitle;
private FromState mFromLabelState;
@Thunk FolderIcon mFolderIcon;
@Thunk
FolderIcon mFolderIcon;
@Thunk FolderPagedView mContent;
@Thunk
FolderPagedView mContent;
public FolderNameEditText mFolderName;
private PageIndicatorDots mPageIndicator;
@ -192,7 +190,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
private int mFooterHeight;
// Cell ranks used for drag and drop
@Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
@Thunk
int mTargetRank, mPrevTargetRank, mEmptyCellRank;
private Path mClipPath;
@ -203,7 +202,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@ViewDebug.IntToString(from = STATE_ANIMATING, to = "STATE_ANIMATING"),
@ViewDebug.IntToString(from = STATE_OPEN, to = "STATE_OPEN"),
})
@Thunk int mState = STATE_NONE;
@Thunk
int mState = STATE_NONE;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mRearrangeOnClose = false;
boolean mItemsInvalidated = false;
@ -221,12 +221,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// Folder scrolling
private int mScrollAreaOffset;
@Thunk int mScrollHintDir = SCROLL_NONE;
@Thunk int mCurrentScrollDir = SCROLL_NONE;
@Thunk
int mScrollHintDir = SCROLL_NONE;
@Thunk
int mCurrentScrollDir = SCROLL_NONE;
private StatsLogManager mStatsLogManager;
@Nullable private FolderWindowInsetsAnimationCallback mFolderWindowInsetsAnimationCallback;
@Nullable
private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
private GradientDrawable mBackground;
@ -234,7 +237,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
* Used to inflate the Workspace from XML.
*
* @param context The application's context.
* @param attrs The attributes set containing the Workspace's customization values.
* @param attrs The attributes set containing the Workspace's customization values.
*/
public Folder(Context context, AttributeSet attrs) {
super(context, attrs);
@ -246,7 +249,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mStatsLogManager = StatsLogManager.newInstance(context);
// We need this view to be focusable in touch mode so that when text editing of the folder
// name is complete, we have something to focus on, thus hiding the cursor and giving
// reliable behavior when clicking the text field (since it will always gain focus on click).
// reliable behavior when clicking the text field (since it will always gain focus on
// click).
setFocusableInTouchMode(true);
}
@ -286,10 +290,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mFooterHeight = getResources().getDimensionPixelSize(R.dimen.folder_label_height);
if (Utilities.ATLEAST_R) {
mFolderWindowInsetsAnimationCallback =
new FolderWindowInsetsAnimationCallback(DISPATCH_MODE_STOP, this);
setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
}
@ -311,14 +313,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (options.isAccessibleDrag) {
mDragController.addDragListener(new AccessibleDragListenerAdapter(
mContent, FolderAccessibilityHelper::new) {
@Override
protected void enableAccessibleDrag(boolean enable) {
super.enableAccessibleDrag(enable);
mFooter.setImportantForAccessibility(enable
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
});
@Override
protected void enableAccessibleDrag(boolean enable) {
super.enableAccessibleDrag(enable);
mFooter.setImportantForAccessibility(enable
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
});
}
mLauncherDelegate.beginDragShared(v, this, options);
@ -539,7 +541,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
*
* @param activityContext The main ActivityContext in which to inflate this Folder. It must also
* be an instance or ContextWrapper around the Launcher activity context.
*
* @return A new UserFolder.
*/
@SuppressLint("InflateParams")
@ -677,6 +678,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mFolderIcon.setIconVisible(false);
mFolderIcon.drawLeaveBehindIfExists();
}
@Override
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
@ -691,7 +693,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
int footerWidth = mContent.getDesiredWidth()
- mFooter.getPaddingLeft() - mFooter.getPaddingRight();
float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
float translation = (footerWidth - textWidth) / 2;
mFolderName.setTranslationX(mContent.mIsRtl ? -translation : translation);
mPageIndicator.prepareEntryAnimation();
@ -705,9 +707,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Override
public void onAnimationEnd(Animator animation) {
mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
.translationX(0)
.setInterpolator(AnimationUtils.loadInterpolator(
getContext(), android.R.interpolator.fast_out_slow_in));
.translationX(0)
.setInterpolator(AnimationUtils.loadInterpolator(
getContext(), android.R.interpolator.fast_out_slow_in));
mPageIndicator.playEntryAnimation();
if (updateAnimationFlag) {
@ -794,8 +796,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Override
public void onAnimationEnd(Animator animation) {
if (Utilities.ATLEAST_R && mFolderWindowInsetsAnimationCallback != null) {
setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
if (Utilities.ATLEAST_R && mKeyboardInsetAnimationCallback != null) {
setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
closeComplete(true);
announceAccessibilityChanges();
@ -1109,7 +1111,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
sTempRect.set(mActivityContext.getFolderBoundingBox());
int left = Utilities.boundToRange(centeredLeft, sTempRect.left, sTempRect.right - width);
int top = Utilities.boundToRange(centeredTop, sTempRect.top, sTempRect.bottom - height);
int[] inOutPosition = new int[] {left, top};
int[] inOutPosition = new int[]{left, top};
mActivityContext.updateOpenFolderPosition(inOutPosition, sTempRect, width, height);
left = inOutPosition[0];
top = inOutPosition[1];
@ -1193,7 +1195,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return mInfo.contents.size();
}
@Thunk void replaceFolderWithFinalItem() {
void replaceFolderWithFinalItem() {
mLauncherDelegate.replaceFolderWithFinalItem(this);
mDestroyed = true;
}
@ -1352,6 +1354,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
v.setVisibility(INVISIBLE);
}
}
public void showItem(WorkspaceItemInfo info) {
View v = getViewForInfo(info);
if (v != null) {
@ -1646,55 +1649,4 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return windowBottomPx - folderBottomPx;
}
/** Callback that animates a folder sliding up above the ime. */
@RequiresApi(api = Build.VERSION_CODES.R)
private static class FolderWindowInsetsAnimationCallback
extends WindowInsetsAnimation.Callback {
private final Folder mFolder;
float mFolderTranslationStart;
float mFolderTranslationEnd;
FolderWindowInsetsAnimationCallback(int dispatchMode, Folder folder) {
super(dispatchMode);
mFolder = folder;
}
@Override
public void onPrepare(@NonNull WindowInsetsAnimation animation) {
mFolderTranslationStart = mFolder.getTranslationY();
}
@NonNull
@Override
public WindowInsetsAnimation.Bounds onStart(
@NonNull WindowInsetsAnimation animation,
@NonNull WindowInsetsAnimation.Bounds bounds) {
mFolderTranslationEnd = mFolder.getTranslationY();
mFolder.setTranslationY(mFolderTranslationStart);
return super.onStart(animation, bounds);
}
@NonNull
@Override
public WindowInsets onProgress(@NonNull WindowInsets windowInsets,
@NonNull List<WindowInsetsAnimation> list) {
if (list.size() == 0) {
mFolder.setTranslationY(0);
return windowInsets;
}
float progress = list.get(0).getInterpolatedFraction();
mFolder.setTranslationY(
Utilities.mapRange(progress, mFolderTranslationStart, mFolderTranslationEnd));
return windowInsets;
}
}
}

View File

@ -37,6 +37,7 @@ public class OnboardingPrefs<T extends Launcher> {
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
public static final String SEARCH_EDU_SEEN = "launcher.search_edu";
public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
/**
* Events that either have happened or have not (booleans).
@ -47,23 +48,28 @@ public class OnboardingPrefs<T extends Launcher> {
SEARCH_EDU_SEEN
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventBoolKey {}
public @interface EventBoolKey {
}
/**
* Events that occur multiple times, which we count up to a max defined in {@link #MAX_COUNTS}.
*/
@StringDef(value = {
HOME_BOUNCE_COUNT,
HOTSEAT_DISCOVERY_TIP_COUNT
HOTSEAT_DISCOVERY_TIP_COUNT,
SEARCH_SNACKBAR_COUNT
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventCountKey {}
public @interface EventCountKey {
}
private static final Map<String, Integer> MAX_COUNTS;
static {
Map<String, Integer> maxCounts = new ArrayMap<>(4);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
}
@ -103,6 +109,7 @@ public class OnboardingPrefs<T extends Launcher> {
/**
* Add 1 to the given event count, if we haven't already reached the max count.
*
* @return Whether we have now reached the max count.
*/
public boolean incrementEventCount(@EventCountKey String eventKey) {