Merge changes from topic "gentle-header" into qt-dev
am: 31b02a613f
Change-Id: I0748e65953628a928c073ee019f90ea054cd1d86
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user