PeopleHub swipe-to-dismiss
Test: manual Change-Id: I9ee003d78f048574e5b9b5b4f297104028eb87a5
This commit is contained in:
@@ -159,6 +159,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
private int mHeadsUpAddStartLocation;
|
||||
private float mHeadsUpLocation;
|
||||
private boolean mIsAppearing;
|
||||
private boolean mDismissed;
|
||||
private boolean mRefocusOnDismiss;
|
||||
|
||||
public ActivatableNotificationView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -1048,6 +1050,27 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
/** Mark that this view has been dismissed. */
|
||||
public void dismiss(boolean refocusOnDismiss) {
|
||||
mDismissed = true;
|
||||
mRefocusOnDismiss = refocusOnDismiss;
|
||||
}
|
||||
|
||||
/** Mark that this view is no longer dismissed. */
|
||||
public void unDismiss() {
|
||||
mDismissed = false;
|
||||
}
|
||||
|
||||
/** Is this view marked as dismissed? */
|
||||
public boolean isDismissed() {
|
||||
return mDismissed;
|
||||
}
|
||||
|
||||
/** Should a re-focus occur upon dismissing this view? */
|
||||
public boolean shouldRefocusOnDismiss() {
|
||||
return mRefocusOnDismiss || isAccessibilityFocused();
|
||||
}
|
||||
|
||||
public interface OnActivatedListener {
|
||||
void onActivated(ActivatableNotificationView view);
|
||||
void onActivationReset(ActivatableNotificationView view);
|
||||
|
||||
@@ -95,6 +95,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||
import com.android.systemui.statusbar.notification.stack.SwipeableView;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
@@ -114,7 +115,7 @@ import java.util.function.Consumer;
|
||||
* the group summary (which contains 1 or more child notifications).
|
||||
*/
|
||||
public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
implements PluginListener<NotificationMenuRowPlugin> {
|
||||
implements PluginListener<NotificationMenuRowPlugin>, SwipeableView {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
|
||||
@@ -288,7 +289,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
};
|
||||
private boolean mForceUnlocked;
|
||||
private boolean mDismissed;
|
||||
private boolean mKeepInParent;
|
||||
private boolean mRemoved;
|
||||
private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
|
||||
@@ -307,7 +307,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
private boolean mHeadsupDisappearRunning;
|
||||
private View mChildAfterViewWhenDismissed;
|
||||
private View mGroupParentWhenDismissed;
|
||||
private boolean mRefocusOnDismiss;
|
||||
private float mContentTransformationAmount;
|
||||
private boolean mIconsVisible = true;
|
||||
private boolean mAboveShelf;
|
||||
@@ -1164,6 +1163,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFinishedInitialization() {
|
||||
return getEntry().hasFinishedInitialization();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a handle to a NotificationMenuRowPlugin whose menu view has been added to our hierarchy,
|
||||
* or null if there is no menu row
|
||||
@@ -1323,11 +1327,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
}
|
||||
|
||||
public void setDismissed(boolean fromAccessibility) {
|
||||
@Override
|
||||
public void dismiss(boolean refocusOnDismiss) {
|
||||
super.dismiss(refocusOnDismiss);
|
||||
setLongPressListener(null);
|
||||
mDismissed = true;
|
||||
mGroupParentWhenDismissed = mNotificationParent;
|
||||
mRefocusOnDismiss = fromAccessibility;
|
||||
mChildAfterViewWhenDismissed = null;
|
||||
mEntry.icon.setDismissed();
|
||||
if (isChildInGroup()) {
|
||||
@@ -1340,10 +1344,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDismissed() {
|
||||
return mDismissed;
|
||||
}
|
||||
|
||||
public boolean keepInParent() {
|
||||
return mKeepInParent;
|
||||
}
|
||||
@@ -1445,7 +1445,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
groupSummary.getRow().performDismiss(fromAccessibility);
|
||||
}
|
||||
}
|
||||
setDismissed(fromAccessibility);
|
||||
dismiss(fromAccessibility);
|
||||
if (mEntry.isClearable()) {
|
||||
// TODO: beverlyt, log dismissal
|
||||
// TODO: track dismiss sentiment
|
||||
@@ -3021,10 +3021,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldRefocusOnDismiss() {
|
||||
return mRefocusOnDismiss || isAccessibilityFocused();
|
||||
}
|
||||
|
||||
public interface OnExpandClickListener {
|
||||
void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -310,6 +309,8 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
|
||||
mParent.removeView(mPeopleHubView);
|
||||
}
|
||||
} else {
|
||||
mPeopleHubView.unDismiss();
|
||||
mPeopleHubView.resetTranslation();
|
||||
if (!currentlyVisible) {
|
||||
if (mPeopleHubView.getTransientContainer() != null) {
|
||||
mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView);
|
||||
@@ -419,8 +420,9 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePeopleHubClick(PendingIntent pendingIntent) {
|
||||
mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent, null, mPeopleHubView);
|
||||
void hidePeopleRow() {
|
||||
mPeopleHubVisible = false;
|
||||
updateSectionBoundaries();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4920,7 +4920,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
} else {
|
||||
child.setMinClipTopAmount(0);
|
||||
}
|
||||
previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child);
|
||||
previousChildWillBeDismissed = canChildBeDismissed(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5523,7 +5523,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
|
||||
performDismissAllAnimations(viewsToHide, closeShade, () -> {
|
||||
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
|
||||
if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) {
|
||||
if (canChildBeDismissed(rowToRemove)) {
|
||||
if (selection == ROWS_ALL) {
|
||||
// TODO: This is a listener method; we shouldn't be calling it. Can we just
|
||||
// call performRemoveNotification as below?
|
||||
@@ -5552,7 +5552,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
private boolean includeChildInDismissAll(
|
||||
ExpandableNotificationRow row,
|
||||
@SelectedRows int selection) {
|
||||
return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection);
|
||||
return canChildBeDismissed(row) && matchesSelection(row, selection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6223,7 +6223,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
*/
|
||||
@Override
|
||||
public void onChildDismissed(View view) {
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
|
||||
if (!(view instanceof ActivatableNotificationView)) {
|
||||
return;
|
||||
}
|
||||
ActivatableNotificationView row = (ActivatableNotificationView) view;
|
||||
if (!row.isDismissed()) {
|
||||
handleChildViewDismissed(view);
|
||||
}
|
||||
@@ -6261,6 +6264,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
row.performDismissWithBlockingHelper(false /* fromAccessibility */);
|
||||
}
|
||||
|
||||
if (view instanceof PeopleHubView) {
|
||||
PeopleHubView row = (PeopleHubView) view;
|
||||
row.dismiss(false);
|
||||
mSectionsManager.hidePeopleRow();
|
||||
}
|
||||
|
||||
if (!isBlockingHelperShown) {
|
||||
mSwipedOutViews.add(view);
|
||||
}
|
||||
@@ -6349,9 +6358,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public boolean canChildBeDismissed(View v) {
|
||||
return StackScrollAlgorithm.canChildBeDismissed(v);
|
||||
return NotificationStackScrollLayout.canChildBeDismissed(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -6361,6 +6370,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean canChildBeDismissed(View v) {
|
||||
if (v instanceof ExpandableNotificationRow) {
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
|
||||
if (row.isBlockingHelperShowingAndTranslationFinished()) {
|
||||
return true;
|
||||
}
|
||||
if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
|
||||
return false;
|
||||
}
|
||||
return row.canViewBeDismissed();
|
||||
}
|
||||
if (v instanceof PeopleHubView) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.INPUT)
|
||||
|
||||
@@ -31,11 +31,10 @@ import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||
|
||||
class NotificationSwipeHelper extends SwipeHelper
|
||||
implements NotificationSwipeActionHelper {
|
||||
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
|
||||
|
||||
@VisibleForTesting
|
||||
protected static final long COVER_MENU_DELAY = 4000;
|
||||
private static final String TAG = "NotificationSwipeHelper";
|
||||
@@ -58,12 +57,7 @@ class NotificationSwipeHelper extends SwipeHelper
|
||||
super(swipeDirection, callback, context, falsingManager);
|
||||
mMenuListener = menuListener;
|
||||
mCallback = callback;
|
||||
mFalsingCheck = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resetExposedMenuView(true /* animate */, true /* force */);
|
||||
}
|
||||
};
|
||||
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
|
||||
}
|
||||
|
||||
public View getTranslatingParentView() {
|
||||
@@ -126,14 +120,14 @@ class NotificationSwipeHelper extends SwipeHelper
|
||||
// Slide back any notifications that might be showing a menu
|
||||
resetExposedMenuView(true /* animate */, false /* force */);
|
||||
|
||||
if (currView instanceof ExpandableNotificationRow) {
|
||||
initializeRow((ExpandableNotificationRow) currView);
|
||||
if (currView instanceof SwipeableView) {
|
||||
initializeRow((SwipeableView) currView);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void initializeRow(ExpandableNotificationRow row) {
|
||||
if (row.getEntry().hasFinishedInitialization()) {
|
||||
protected void initializeRow(SwipeableView row) {
|
||||
if (row.hasFinishedInitialization()) {
|
||||
mCurrMenuRow = row.createMenu();
|
||||
if (mCurrMenuRow != null) {
|
||||
mCurrMenuRow.setMenuClickListener(mMenuListener);
|
||||
@@ -304,8 +298,8 @@ class NotificationSwipeHelper extends SwipeHelper
|
||||
@Override
|
||||
public Animator getViewTranslationAnimator(View v, float target,
|
||||
ValueAnimator.AnimatorUpdateListener listener) {
|
||||
if (v instanceof ExpandableNotificationRow) {
|
||||
return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
|
||||
if (v instanceof SwipeableView) {
|
||||
return ((SwipeableView) v).getTranslateViewAnimator(target, listener);
|
||||
} else {
|
||||
return superGetViewTranslationAnimator(v, target, listener);
|
||||
}
|
||||
@@ -313,15 +307,15 @@ class NotificationSwipeHelper extends SwipeHelper
|
||||
|
||||
@Override
|
||||
public void setTranslation(View v, float translate) {
|
||||
if (v instanceof ExpandableNotificationRow) {
|
||||
((ExpandableNotificationRow) v).setTranslation(translate);
|
||||
if (v instanceof SwipeableView) {
|
||||
((SwipeableView) v).setTranslation(translate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslation(View v) {
|
||||
if (v instanceof ExpandableNotificationRow) {
|
||||
return ((ExpandableNotificationRow) v).getTranslation();
|
||||
if (v instanceof SwipeableView) {
|
||||
return ((SwipeableView) v).getTranslation();
|
||||
}
|
||||
else {
|
||||
return 0f;
|
||||
@@ -410,8 +404,8 @@ class NotificationSwipeHelper extends SwipeHelper
|
||||
if (anim != null) {
|
||||
anim.start();
|
||||
}
|
||||
} else if (prevMenuExposedView instanceof ExpandableNotificationRow) {
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView;
|
||||
} else if (prevMenuExposedView instanceof SwipeableView) {
|
||||
SwipeableView row = (SwipeableView) prevMenuExposedView;
|
||||
if (!row.isRemoved()) {
|
||||
row.resetTranslation();
|
||||
}
|
||||
|
||||
@@ -16,23 +16,39 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.stack
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.util.FloatProperty
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.notification.people.PersonViewModel
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
|
||||
import com.android.systemui.statusbar.notification.people.DataListener
|
||||
import com.android.systemui.statusbar.notification.people.PersonViewModel
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
|
||||
|
||||
private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") {
|
||||
override fun setValue(view: PeopleHubView, value: Float) {
|
||||
view.translation = value
|
||||
}
|
||||
|
||||
override fun get(view: PeopleHubView) = view.translation
|
||||
}
|
||||
|
||||
class PeopleHubView(context: Context, attrs: AttributeSet) :
|
||||
ActivatableNotificationView(context, attrs) {
|
||||
ActivatableNotificationView(context, attrs), SwipeableView {
|
||||
|
||||
private lateinit var contents: ViewGroup
|
||||
private lateinit var personControllers: List<PersonDataListenerImpl>
|
||||
private var translateAnim: ObjectAnimator? = null
|
||||
|
||||
val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
|
||||
get() = personControllers.asSequence()
|
||||
|
||||
@@ -49,6 +65,34 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
|
||||
|
||||
override fun getContentView(): View = contents
|
||||
|
||||
override fun hasFinishedInitialization(): Boolean = true
|
||||
|
||||
override fun createMenu(): NotificationMenuRowPlugin? = null
|
||||
|
||||
override fun getTranslateViewAnimator(
|
||||
leftTarget: Float,
|
||||
listener: ValueAnimator.AnimatorUpdateListener?
|
||||
): Animator =
|
||||
ObjectAnimator
|
||||
.ofFloat(this, TRANSLATE_CONTENT, leftTarget)
|
||||
.apply {
|
||||
listener?.let { addUpdateListener(listener) }
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(anim: Animator) {
|
||||
translateAnim = null
|
||||
}
|
||||
})
|
||||
}
|
||||
.also {
|
||||
translateAnim?.cancel()
|
||||
translateAnim = it
|
||||
}
|
||||
|
||||
override fun resetTranslation() {
|
||||
translateAnim?.cancel()
|
||||
translationX = 0f
|
||||
}
|
||||
|
||||
private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) :
|
||||
DataListener<PersonViewModel?> {
|
||||
|
||||
|
||||
@@ -195,20 +195,6 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canChildBeDismissed(View v) {
|
||||
if (!(v instanceof ExpandableNotificationRow)) {
|
||||
return false;
|
||||
}
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
|
||||
if (row.isBlockingHelperShowingAndTranslationFinished()) {
|
||||
return true;
|
||||
}
|
||||
if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
|
||||
return false;
|
||||
}
|
||||
return row.canViewBeDismissed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the dimmed, activated and hiding sensitive states of the children.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.systemui.statusbar.notification.stack;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
|
||||
/** A View that is swipeable inside of the notification shade. */
|
||||
public interface SwipeableView {
|
||||
|
||||
/** Has this view finished initializing? */
|
||||
boolean hasFinishedInitialization();
|
||||
|
||||
/** Optionally creates a menu for this view. */
|
||||
@Nullable NotificationMenuRowPlugin createMenu();
|
||||
|
||||
/** Animator for translating the view, simulating a swipe. */
|
||||
Animator getTranslateViewAnimator(
|
||||
float leftTarget, ValueAnimator.AnimatorUpdateListener listener);
|
||||
|
||||
/** Sets the translation amount for an in-progress swipe. */
|
||||
void setTranslation(float translate);
|
||||
|
||||
/** Gets the current translation amount. */
|
||||
float getTranslation();
|
||||
|
||||
/** Has this view been removed? */
|
||||
boolean isRemoved();
|
||||
|
||||
/** Resets the swipe translation back to zero state. */
|
||||
void resetTranslation();
|
||||
}
|
||||
@@ -226,7 +226,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
|
||||
any(NotificationMenuRowPlugin.MenuItem.class));
|
||||
reset(listener);
|
||||
|
||||
mGroupRow.setDismissed(true);
|
||||
mGroupRow.dismiss(true);
|
||||
mGroupRow.doLongClickCallback(0,0);
|
||||
verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0),
|
||||
any(NotificationMenuRowPlugin.MenuItem.class));
|
||||
|
||||
Reference in New Issue
Block a user