Merge changes from topic "gentle-header" into qt-dev

am: 31b02a613f

Change-Id: I0748e65953628a928c073ee019f90ea054cd1d86
This commit is contained in:
Ned Burns
2019-05-07 14:52:53 -07:00
committed by android-build-merger
7 changed files with 197 additions and 38 deletions

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:fillColor="#9AA0A6"
android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/>
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:fillColor="#5F6368"
android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
</vector>

View File

@@ -50,9 +50,10 @@
/>
<ImageView
android:id="@+id/btn_clear_all"
android:visibility="gone"
android:layout_width="@dimen/notification_section_header_height"
android:layout_height="@dimen/notification_section_header_height"
android:layout_marginRight="4dp"
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
/>
</LinearLayout>

View File

@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
@@ -42,6 +44,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
private SectionHeaderView mGentleHeader;
private boolean mGentleHeaderVisible = false;
@Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
NotificationSectionsManager(
NotificationStackScrollLayout parent,
@@ -70,12 +73,18 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
mGentleHeader = (SectionHeaderView) LayoutInflater.from(context).inflate(
R.layout.status_bar_notification_section_header, mParent, false);
mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick);
if (oldPos != -1) {
mParent.addView(mGentleHeader, oldPos);
}
}
/** Listener for when the "clear all" buttton is clciked on the gentle notification header. */
void setOnClearGentleNotifsClickListener(View.OnClickListener listener) {
mOnClearGentleNotifsClickListener = listener;
}
/** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
void onUiModeChanged() {
mGentleHeader.onUiModeChanged();
@@ -111,6 +120,9 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
}
adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
mGentleHeader.setAreThereDismissableGentleNotifs(
mParent.hasActiveClearableNotifications(ROWS_GENTLE));
}
private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) {
@@ -225,4 +237,10 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
true,
Intent.FLAG_ACTIVITY_SINGLE_TOP);
}
private void onClearGentleNotifsClick(View v) {
if (mOnClearGentleNotifsClickListener != null) {
mOnClearGentleNotifsClickListener.onClick(v);
}
}
}

View File

@@ -23,10 +23,13 @@ import static com.android.systemui.statusbar.notification.stack.StackStateAnimat
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperManager;
@@ -143,6 +146,7 @@ import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -525,12 +529,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
mAmbientPulseManager = ambientPulseManager;
mSectionsManager =
new NotificationSectionsManager(
this,
activityStarter,
NotificationUtils.useNewInterruptionModel(context));
mSectionsManager.inflateViews(context);
mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
// Leave the shade open if there will be other notifs left over to clear
final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
clearNotifications(ROWS_GENTLE, closeShade);
});
mAmbientState = new AmbientState(context, mSectionsManager);
mRoundnessManager = notificationRoundnessManager;
mBgColor = context.getColor(R.color.notification_shade_background_color);
@@ -672,7 +683,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
boolean showFooterView = (showDismissView ||
mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
&& mStatusBarState != StatusBarState.KEYGUARD
@@ -685,14 +696,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* Return whether there are any clearable notifications
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasActiveClearableNotifications() {
public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (!(child instanceof ExpandableNotificationRow)) {
continue;
}
if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
if (row.canViewBeDismissed() && matchesSelection(row, selection)) {
return true;
}
}
@@ -1695,11 +1707,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return mScrollingEnabled;
}
@ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
@@ -4917,7 +4924,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
} else {
child.setMinClipTopAmount(0);
}
previousChildWillBeDismissed = canChildBeDismissed(child);
previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child);
}
}
@@ -5473,7 +5480,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void clearAllNotifications() {
private void clearNotifications(
@SelectedRows int selection,
boolean closeShade) {
// animate-swipe all dismissable notifications, then animate the shade closed
int numChildren = getChildCount();
@@ -5485,7 +5494,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
boolean parentVisible = false;
boolean hasClipBounds = child.getClipBounds(mTmpRect);
if (canChildBeDismissed(child)) {
if (includeChildInDismissAll(row, selection)) {
viewsToRemove.add(row);
if (child.getVisibility() == View.VISIBLE
&& (!hasClipBounds || mTmpRect.height() > 0)) {
@@ -5499,51 +5508,94 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
List<ExpandableNotificationRow> children = row.getNotificationChildren();
if (children != null) {
for (ExpandableNotificationRow childRow : children) {
viewsToRemove.add(childRow);
if (parentVisible && row.areChildrenExpanded()
&& canChildBeDismissed(childRow)) {
hasClipBounds = childRow.getClipBounds(mTmpRect);
if (childRow.getVisibility() == View.VISIBLE
&& (!hasClipBounds || mTmpRect.height() > 0)) {
viewsToHide.add(childRow);
if (includeChildInDismissAll(row, selection)) {
viewsToRemove.add(childRow);
if (parentVisible && row.areChildrenExpanded()) {
hasClipBounds = childRow.getClipBounds(mTmpRect);
if (childRow.getVisibility() == View.VISIBLE
&& (!hasClipBounds || mTmpRect.height() > 0)) {
viewsToHide.add(childRow);
}
}
}
}
}
}
}
if (viewsToRemove.isEmpty()) {
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
if (closeShade) {
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
return;
}
mShadeController.addPostCollapseAction(() -> {
setDismissAllInProgress(false);
performDismissAllAnimations(viewsToHide, closeShade, () -> {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
mEntryManager.removeNotification(rowToRemove.getEntry().key, null /* ranking */,
NotificationListenerService.REASON_CANCEL_ALL);
if (StackScrollAlgorithm.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?
mEntryManager.removeNotification(
rowToRemove.getEntry().key,
null /* ranking */,
NotificationListenerService.REASON_CANCEL_ALL);
} else {
mEntryManager.performRemoveNotification(
rowToRemove.getEntry().notification,
NotificationListenerService.REASON_CANCEL_ALL);
}
} else {
rowToRemove.resetTranslation();
}
}
try {
mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
} catch (Exception ex) {
if (selection == ROWS_ALL) {
try {
mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
} catch (Exception ex) {
}
}
});
performDismissAllAnimations(viewsToHide);
}
private boolean includeChildInDismissAll(
ExpandableNotificationRow row,
@SelectedRows int selection) {
return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection);
}
/**
* Given a list of rows, animates them away in a staggered fashion as if they were dismissed.
* Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete
* handler.
*
* @param hideAnimatedList List of rows to animated away. Should only be views that are
* currently visible, or else the stagger will look funky.
* @param closeShade Whether to close the shade after the stagger animation completes.
* @param onAnimationComplete Called after the entire animation completes (including the shade
* closing if appropriate). The rows must be dismissed for real here.
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
Runnable animationFinishAction = () -> {
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
private void performDismissAllAnimations(
final ArrayList<View> hideAnimatedList,
final boolean closeShade,
final Runnable onAnimationComplete) {
final Runnable onSlideAwayAnimationComplete = () -> {
if (closeShade) {
mShadeController.addPostCollapseAction(() -> {
setDismissAllInProgress(false);
onAnimationComplete.run();
});
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
setDismissAllInProgress(false);
onAnimationComplete.run();
}
};
if (hideAnimatedList.isEmpty()) {
animationFinishAction.run();
onSlideAwayAnimationComplete.run();
return;
}
@@ -5560,7 +5612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
View view = hideAnimatedList.get(i);
Runnable endRunnable = null;
if (i == 0) {
endRunnable = animationFinishAction;
endRunnable = onSlideAwayAnimationComplete;
}
dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
@@ -5575,7 +5627,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
R.layout.status_bar_notification_footer, this, false);
footerView.setDismissButtonClickListener(v -> {
mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
clearAllNotifications();
clearNotifications(ROWS_ALL, true /* closeShade */);
});
footerView.setManageButtonClickListener(this::manageNotifications);
setFooterView(footerView);
@@ -5782,6 +5834,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mSwipeHelper.resetExposedMenuView(animate, force);
}
private static boolean matchesSelection(
ExpandableNotificationRow row,
@SelectedRows int selection) {
switch (selection) {
case ROWS_ALL:
return true;
case ROWS_HIGH_PRIORITY:
return row.getEntry().isHighPriority();
case ROWS_GENTLE:
return !row.getEntry().isHighPriority();
default:
throw new IllegalArgumentException("Unknown selection: " + selection);
}
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
static class AnimationEvent {
@@ -6266,7 +6333,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public boolean canChildBeDismissed(View v) {
return NotificationStackScrollLayout.this.canChildBeDismissed(v);
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@Override
@@ -6473,4 +6540,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public ExpandHelper.Callback getExpandHelperCallback() {
return mExpandHelperCallback;
}
/** Enum for selecting some or all notification rows (does not included non-notif views). */
@Retention(SOURCE)
@IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE})
public @interface SelectedRows {}
/** All rows representing notifs. */
public static final int ROWS_ALL = 0;
/** Only rows where entry.isHighPriority() is true. */
public static final int ROWS_HIGH_PRIORITY = 1;
/** Only rows where entry.isHighPriority() is false. */
public static final int ROWS_GENTLE = 2;
}

View File

@@ -60,6 +60,12 @@ public class SectionHeaderView extends ActivatableNotificationView {
updateBackgroundColors();
mLabelView.setTextColor(
getContext().getColor(R.color.notification_section_header_label_color));
mClearAllButton.setImageResource(
R.drawable.status_bar_notification_section_header_clear_btn);
}
void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) {
mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE);
}
@Override
@@ -79,4 +85,9 @@ public class SectionHeaderView extends ActivatableNotificationView {
void setOnHeaderClickListener(View.OnClickListener listener) {
mContents.setOnClickListener(listener);
}
/** Fired when the user clicks on the "X" button on the far right of the header. */
void setOnClearAllClickListener(View.OnClickListener listener) {
mClearAllButton.setOnClickListener(listener);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.SysUiServiceProvider.getComponent;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.animation.Animator;
@@ -2992,7 +2993,7 @@ public class NotificationPanelView extends PanelView implements
}
public boolean hasActiveClearableNotifications() {
return mNotificationStackScroller.hasActiveClearableNotifications();
return mNotificationStackScroller.hasActiveClearableNotifications(ROWS_ALL);
}
@Override