Update snooze visuals to match latest design

Also updates it so that the height animates going from collapsed / expanded

Test: manual / runtest systemui
Bug: 36249479
Change-Id: Ice10e42986eddc9b87ba79cd00dfc59fefef5464
This commit is contained in:
Mady Mellor
2017-03-30 13:23:29 -07:00
parent ab312729ce
commit e09fb7029a
11 changed files with 207 additions and 117 deletions

View File

@@ -19,47 +19,56 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/snooze_snackbar_min_height"
android:id="@+id/notification_snooze"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:background="@color/snooze_snackbar_bg">
<TextView
android:id="@+id/snooze_option_default"
style="@style/TextAppearance.SnoozeSnackBar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:drawableTint="@android:color/white"
android:drawableEnd="@drawable/notification_expand_more"/>
<android.widget.Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
/>
<TextView
android:id="@+id/undo"
style="@style/TextAppearance.SnoozeSnackBar.Button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:background="@drawable/btn_borderless_rect"
android:layout_gravity="end"
android:text="@string/snooze_undo" />
android:orientation="vertical"
android:background="@color/notification_guts_bg_color"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/notification_snooze"
android:layout_height="@dimen/snooze_snackbar_min_height">
<TextView
android:id="@+id/snooze_option_default"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:paddingStart="16dp"
android:textColor="#DD000000"
android:paddingEnd="4dp"/>
<ImageView
android:id="@+id/expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/snooze_option_default"
android:layout_centerVertical="true"
android:paddingTop="1dp"
android:tint="#9E9E9E" />
<TextView
android:id="@+id/undo"
style="@style/TextAppearance.NotificationInfo.Button"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginEnd="8dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:text="@string/snooze_undo" />
</RelativeLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#9E9E9E" />
<LinearLayout
android:id="@+id/snooze_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="vertical"/>
android:orientation="vertical" />
</com.android.systemui.statusbar.NotificationSnooze>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017, 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.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:gravity="center_vertical"
android:textSize="14sp"
android:textColor="#DD000000"/>

View File

@@ -96,10 +96,6 @@
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
<!-- Colors of the snooze menu reached via snooze icon behind a notification -->
<color name="snooze_snackbar_bg">#FF4A4A4A</color>
<color name="snooze_snackbar_text">#FFA6BAFF</color>
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>

View File

@@ -119,7 +119,7 @@
<dimen name="notification_menu_icon_padding">20dp</dimen>
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">48dp</dimen>
<dimen name="snooze_snackbar_min_height">56dp</dimen>
<!-- The text size of options in the snooze menu. -->
<dimen name="snooze_option_text_size">14sp</dimen>

View File

@@ -1493,8 +1493,6 @@
<string name="snooze_option_30_min">30 minutes</string>
<!-- Notification: Menu row: Snooze options: 1 hour option. [CHAR LIMIT=50]-->
<string name="snooze_option_1_hour">1 hour</string>
<!-- Notification: Menu row: Snooze options: cancel snoozing option. [CHAR LIMIT=50] -->
<string name="snooze_option_dont_snooze">Cancel</string>
<!-- Notification: Menu row: Snooze undo button label. [CHAR LIMIT=50]-->
<string name="snooze_undo">UNDO</string>

View File

@@ -386,20 +386,6 @@
<item name="android:paddingEnd">8dp</item>
</style>
<style name="TextAppearance.SnoozeSnackBar">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textColor">@android:color/white</item>
</style>
<style name="TextAppearance.SnoozeSnackBar.Button">
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@color/snooze_snackbar_text</item>
</style>
<style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>

View File

@@ -1490,7 +1490,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return getActualHeight();
}
if (mGuts != null && mGuts.isExposed()) {
return mGuts.getHeight();
return mGuts.getIntrinsicHeight();
} else if ((isChildInGroup() && !isGroupExpanded())) {
return mPrivateLayout.getMinHeight();
} else if (mShowAmbient) {
@@ -1831,7 +1831,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public int getMinHeight() {
if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
if (mGuts != null && mGuts.isExposed()) {
return mGuts.getIntrinsicHeight();
} else if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
} else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
return mChildrenContainer.getMinHeight();

View File

@@ -73,7 +73,8 @@ public class NotificationGuts extends FrameLayout {
private Handler mHandler;
private Runnable mFalsingCheck;
private boolean mNeedsFalsingProtection;
private OnGutsClosedListener mListener;
private OnGutsClosedListener mClosedListener;
private OnHeightChangedListener mHeightListener;
private GutsContent mGutsContent;
@@ -86,6 +87,11 @@ public class NotificationGuts extends FrameLayout {
*/
public View getContentView();
/**
* @return the actual height of the content.
*/
public int getActualHeight();
/**
* Called when the guts view have been told to close, typically after an outside
* interaction. Returning {@code true} here will prevent the guts view to close.
@@ -102,6 +108,10 @@ public class NotificationGuts extends FrameLayout {
public void onGutsClosed(NotificationGuts guts);
}
public interface OnHeightChangedListener {
public void onHeightChanged(NotificationGuts guts);
}
interface OnSettingsClickListener {
void onClick(View v, int appUid);
}
@@ -125,7 +135,6 @@ public class NotificationGuts extends FrameLayout {
public NotificationGuts(Context context) {
this(context, null);
}
public void setGutsContent(GutsContent content) {
@@ -189,8 +198,8 @@ public class NotificationGuts extends FrameLayout {
public void closeControls(int x, int y, boolean save) {
if (getWindowToken() == null) {
if (mListener != null) {
mListener.onGutsClosed(this);
if (mClosedListener != null) {
mClosedListener.onGutsClosed(this);
}
return;
}
@@ -198,8 +207,8 @@ public class NotificationGuts extends FrameLayout {
animateClose(x, y);
}
setExposed(false, mNeedsFalsingProtection);
if (mListener != null) {
mListener.onGutsClosed(this);
if (mClosedListener != null) {
mClosedListener.onGutsClosed(this);
}
}
@@ -234,6 +243,10 @@ public class NotificationGuts extends FrameLayout {
return mActualHeight;
}
public int getIntrinsicHeight() {
return mGutsContent != null && mExposed ? mGutsContent.getActualHeight() : getHeight();
}
public void setClipTopAmount(int clipTopAmount) {
mClipTopAmount = clipTopAmount;
invalidate();
@@ -251,7 +264,17 @@ public class NotificationGuts extends FrameLayout {
}
public void setClosedListener(OnGutsClosedListener listener) {
mListener = listener;
mClosedListener = listener;
}
public void setHeightChangedListener(OnHeightChangedListener listener) {
mHeightListener = listener;
}
protected void onHeightChanged() {
if (mHeightListener != null) {
mHeightListener.onHeightChanged(this);
}
}
public void setExposed(boolean exposed, boolean needsFalsingProtection) {

View File

@@ -386,4 +386,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
return false;
}
@Override
public int getActualHeight() {
return getHeight();
}
}

View File

@@ -21,35 +21,47 @@ import java.util.List;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
public class NotificationSnooze extends LinearLayout
implements NotificationGuts.GutsContent, View.OnClickListener {
private static final int MAX_ASSISTANT_SUGGESTIONS = 2;
private static final int MAX_ASSISTANT_SUGGESTIONS = 1;
private NotificationGuts mGutsContainer;
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
private TextView mSelectedOptionText;
private TextView mUndoButton;
private ViewGroup mSnoozeOptionView;
private ImageView mExpandButton;
private View mDivider;
private ViewGroup mSnoozeOptionContainer;
private List<SnoozeOption> mSnoozeOptions;
private boolean mSnoozing;
private int mCollapsedHeight;
private SnoozeOption mSelectedOption;
private boolean mSnoozing;
private boolean mExpanded;
private AnimatorSet mExpandAnimation;
public NotificationSnooze(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -58,16 +70,21 @@ public class NotificationSnooze extends LinearLayout
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.snooze_snackbar_min_height);
findViewById(R.id.notification_snooze).setOnClickListener(this);
mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default);
mUndoButton = (TextView) findViewById(R.id.undo);
mUndoButton.setOnClickListener(this);
mExpandButton = (ImageView) findViewById(R.id.expand_button);
mDivider = findViewById(R.id.divider);
mDivider.setAlpha(0f);
mSnoozeOptionContainer = (ViewGroup) findViewById(R.id.snooze_options);
mSnoozeOptionContainer.setAlpha(0f);
// Create the different options based on list
mSnoozeOptions = getDefaultSnoozeOptions();
createOptionViews();
// Snackbar
mSelectedOptionText = findViewById(R.id.snooze_option_default);
mSelectedOptionText.setOnClickListener(this);
mUndoButton = findViewById(R.id.undo);
mUndoButton.setOnClickListener(this);
// Default to first option in list
setSelected(mSnoozeOptions.get(0));
}
@@ -96,52 +113,68 @@ public class NotificationSnooze extends LinearLayout
private SnoozeOption createOption(int descriptionResId, int minutes) {
Resources res = getResources();
String resultText = String.format(
res.getString(R.string.snoozed_for_time), res.getString(descriptionResId));
return new SnoozeOption(null, minutes, res.getString(descriptionResId), resultText);
final String description = res.getString(descriptionResId);
String resultText = String.format(res.getString(R.string.snoozed_for_time), description);
SpannableString string = new SpannableString(resultText);
string.setSpan(new StyleSpan(Typeface.BOLD),
resultText.length() - description.length(), resultText.length(), 0 /* flags */);
return new SnoozeOption(null, minutes, res.getString(descriptionResId), string);
}
private void createOptionViews() {
mSnoozeOptionView = findViewById(R.id.snooze_options);
mSnoozeOptionView.removeAllViews();
mSnoozeOptionView.setVisibility(View.GONE);
final Resources res = getResources();
final int textSize = res.getDimensionPixelSize(R.dimen.snooze_option_text_size);
final int p = res.getDimensionPixelSize(R.dimen.snooze_option_padding);
// Add all the options
mSnoozeOptionContainer.removeAllViews();
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < mSnoozeOptions.size(); i++) {
SnoozeOption option = mSnoozeOptions.get(i);
TextView tv = new TextView(getContext());
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
tv.setPadding(p, p, p, p);
mSnoozeOptionView.addView(tv);
TextView tv = (TextView) inflater.inflate(R.layout.notification_snooze_option,
mSnoozeOptionContainer, false);
mSnoozeOptionContainer.addView(tv);
tv.setText(option.description);
tv.setTag(option);
tv.setOnClickListener(this);
}
}
// Add the undo option as final item
TextView tv = new TextView(getContext());
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
tv.setPadding(p, p, p, p);
mSnoozeOptionView.addView(tv);
tv.setText(R.string.snooze_option_dont_snooze);
tv.setOnClickListener(this);
private void hideSelectedOption() {
final int childCount = mSnoozeOptionContainer.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = mSnoozeOptionContainer.getChildAt(i);
child.setVisibility(child.getTag() == mSelectedOption ? View.GONE : View.VISIBLE);
}
}
private void showSnoozeOptions(boolean show) {
mSelectedOptionText.setVisibility(show ? View.GONE : View.VISIBLE);
mUndoButton.setVisibility(show ? View.GONE : View.VISIBLE);
mSnoozeOptionView.setVisibility(show ? View.VISIBLE : View.GONE);
mExpanded = show;
animateSnoozeOptions(show);
int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification
: com.android.internal.R.drawable.ic_expand_notification;
mExpandButton.setImageResource(drawableId);
if (mGutsContainer != null) {
mGutsContainer.onHeightChanged();
}
}
private void animateSnoozeOptions(boolean show) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
}
ObjectAnimator dividerAnim = ObjectAnimator.ofFloat(mDivider, View.ALPHA,
mDivider.getAlpha(), show ? 1f : 0f);
ObjectAnimator optionAnim = ObjectAnimator.ofFloat(mSnoozeOptionContainer, View.ALPHA,
mSnoozeOptionContainer.getAlpha(), show ? 1f : 0f);
mExpandAnimation = new AnimatorSet();
mExpandAnimation.playTogether(dividerAnim, optionAnim);
mExpandAnimation.setDuration(150);
mExpandAnimation.setInterpolator(show ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
mExpandAnimation.start();
}
private void setSelected(SnoozeOption option) {
mSelectedOption = option;
mSelectedOptionText.setText(option.confirmation);
showSnoozeOptions(false);
hideSelectedOption();
}
@Override
@@ -153,17 +186,28 @@ public class NotificationSnooze extends LinearLayout
final SnoozeOption tag = (SnoozeOption) v.getTag();
if (tag != null) {
setSelected(tag);
} else if (id == R.id.snooze_option_default) {
// Show more snooze options
showSnoozeOptions(true);
} else if (id == R.id.notification_snooze) {
// Toggle snooze options
showSnoozeOptions(!mExpanded);
} else {
undoSnooze();
// Undo snooze was selected
mSelectedOption = null;
int[] parentLoc = new int[2];
int[] targetLoc = new int[2];
mGutsContainer.getLocationOnScreen(parentLoc);
v.getLocationOnScreen(targetLoc);
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
final int x = targetLoc[0] - parentLoc[0] + centerX;
final int y = targetLoc[1] - parentLoc[1] + centerY;
showSnoozeOptions(false);
mGutsContainer.closeControls(x, y, false /* save */);
}
}
private void undoSnooze() {
mSelectedOption = null;
mGutsContainer.closeControls(-1 /* x */, -1 /* y */, true /* notify */);
@Override
public int getActualHeight() {
return mExpanded ? getHeight() : mCollapsedHeight;
}
@Override
@@ -173,6 +217,8 @@ public class NotificationSnooze extends LinearLayout
@Override
public View getContentView() {
// Reset the view before use
setSelected(mSnoozeOptions.get(0));
return this;
}
@@ -197,11 +243,8 @@ public class NotificationSnooze extends LinearLayout
mSnoozing = true;
mSnoozeListener.snooze(mSbn, mSelectedOption);
return true;
} else {
// Reset the view once it's closed
setSelected(mSnoozeOptions.get(0));
showSnoozeOptions(false);
}
// The view should be closed
return false;
}
}

View File

@@ -5774,6 +5774,9 @@ public class StatusBar extends SystemUI implements DemoMode,
snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper());
snoozeGuts.setStatusBarNotification(sbn);
snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria);
guts.setHeightChangedListener((NotificationGuts g) -> {
mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */);
});
}
if (gutsView instanceof NotificationInfo) {