Add snooze to notification menu row

Moves the snooze plugin code into system UI.
Does not include assistant suggestions.

Test: manual
Change-Id: Ie2c51d65381530c9a72cd8a871efdbf0d63da490
This commit is contained in:
Mady Mellor
2017-01-25 13:16:03 -08:00
parent 3e6552036e
commit 04d7a0fca0
9 changed files with 324 additions and 8 deletions

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"
android:fillColor="#757575"/>
<path
android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"
android:fillColor="#757575"/>
</vector>

View File

@@ -0,0 +1,65 @@
<?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.
-->
<com.android.systemui.statusbar.NotificationSnooze
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" />
<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"/>
</com.android.systemui.statusbar.NotificationSnooze>

View File

@@ -103,6 +103,10 @@
<color name="notification_guts_icon_tint">#8a000000</color>
<color name="notification_guts_disabled_icon_tint">#4d000000</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

@@ -112,6 +112,15 @@
<!-- The space around a notification menu item -->
<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>
<!-- The text size of options in the snooze menu. -->
<dimen name="snooze_option_text_size">14sp</dimen>
<!-- The padding around options int the snooze menu. -->
<dimen name="snooze_option_padding">8dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dp</dimen>

View File

@@ -1381,6 +1381,21 @@
<!-- Notification: Menu row: Content description for the gear menu item. [CHAR LIMIT=NONE] -->
<string name="notification_menu_gear_description">notification controls</string>
<!-- Notification: Menu row: Content description for the snooze icon. [CHAR LIMIT=NONE] -->
<string name="notification_menu_snooze_description">notification snooze options</string>
<!-- Notification: Menu row: Snooze options: 15 minute option. [CHAR LIMIT=50]-->
<string name="snooze_option_15_min">15 minutes</string>
<!-- Notification: Menu row: Snooze options: 30 minute option. [CHAR LIMIT=50]-->
<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 undo button label. [CHAR LIMIT=50]-->
<string name="snooze_undo">UNDO</string>
<!-- Notification: Menu row: Snooze: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
<string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
<!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
<string name="battery_panel_title">Battery usage</string>

View File

@@ -383,6 +383,20 @@
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="TextAppearance.SnoozeSnackBar">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">roboto-regular</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

@@ -286,7 +286,7 @@ public class SwipeHelper implements Gefingerpoken {
final int x = (int) ev.getRawX() - mTmpPos[0];
final int y = (int) ev.getRawY() - mTmpPos[1];
mLongPressListener.onLongPress(mCurrView, x, y,
NotificationMenuRow.getSettingsMenuItem(mContext));
NotificationMenuRow.getLongpressMenuItem(mContext));
}
}
};

View File

@@ -85,7 +85,7 @@ public class NotificationMenuRow extends FrameLayout
PluginManager.getInstance(getContext()).addPluginListener(
NotificationMenuRowProvider.ACTION, this,
NotificationMenuRowProvider.VERSION, false /* Allow multiple */);
mMenuItems.add(getSettingsMenuItem(context));
mMenuItems.addAll(getDefaultNotificationMenuItems());
}
@Override
@@ -99,22 +99,43 @@ public class NotificationMenuRow extends FrameLayout
updateMenu(false /* notify */);
}
public static MenuItem getSettingsMenuItem(Context context) {
Drawable d = context.getResources().getDrawable(R.drawable.ic_settings);
String s = context.getResources().getString(R.string.notification_menu_gear_description);
NotificationInfo content = (NotificationInfo) LayoutInflater.from(context).inflate(
public static MenuItem getLongpressMenuItem(Context context) {
Resources res = context.getResources();
Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
String settingsDescription = res.getString(R.string.notification_menu_gear_description);
NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(context).inflate(
R.layout.notification_info, null, false);
MenuItem settings = new MenuItem(d, s, content);
MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
return settings;
}
public ArrayList<MenuItem> getDefaultNotificationMenuItems() {
ArrayList<MenuItem> items = new ArrayList<MenuItem>();
Resources res = getResources();
Drawable snoozeIcon = res.getDrawable(R.drawable.ic_snooze);
NotificationSnooze content = (NotificationSnooze) LayoutInflater.from(mContext)
.inflate(R.layout.notification_snooze, null, false);
String snoozeDescription = res.getString(R.string.notification_menu_snooze_description);
MenuItem snooze = new MenuItem(snoozeIcon, snoozeDescription, content);
items.add(snooze);
Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
String settingsDescription = res.getString(R.string.notification_menu_gear_description);
NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(mContext).inflate(
R.layout.notification_info, null, false);
MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
items.add(settings);
return items;
}
private void updateMenu(boolean notify) {
removeAllViews();
mMenuItems.clear();
if (mMenuProvider != null) {
mMenuItems.addAll(mMenuProvider.getMenuItems(getContext()));
}
mMenuItems.add(getSettingsMenuItem(getContext()));
mMenuItems.addAll(getDefaultNotificationMenuItems());
for (int i = 0; i < mMenuItems.size(); i++) {
final View v = createMenuView(mMenuItems.get(i));
mMenuItems.get(i).menuView = v;

View File

@@ -0,0 +1,176 @@
package com.android.systemui.statusbar;
/*
* Copyright (C) 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
*/
import java.util.ArrayList;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.android.systemui.R;
public class NotificationSnooze extends LinearLayout
implements NotificationMenuRowProvider.SnoozeGutsContent, View.OnClickListener {
private GutsInteractionListener mGutsInteractionListener;
private SnoozeListener mSnoozeListener;
private StatusBarNotification mSbn;
private TextView mSelectedOption;
private TextView mUndo;
private ViewGroup mSnoozeOptionView;
private long mTimeToSnooze;
// Default is the first option in this list
private static final int[] SNOOZE_OPTIONS = {
R.string.snooze_option_15_min, R.string.snooze_option_30_min,
R.string.snooze_option_1_hour
};
public NotificationSnooze(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// Create the different options based on list
createOptionViews();
// Snackbar
mSelectedOption = (TextView) findViewById(R.id.snooze_option_default);
mSelectedOption.setOnClickListener(this);
mUndo = (TextView) findViewById(R.id.undo);
mUndo.setOnClickListener(this);
// Default to first option in list
setTimeToSnooze(SNOOZE_OPTIONS[0]);
}
private void createOptionViews() {
mSnoozeOptionView = (ViewGroup) findViewById(R.id.snooze_options);
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);
for (int i = 0; i < SNOOZE_OPTIONS.length; 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);
tv.setText(SNOOZE_OPTIONS[i]);
tv.setTag(SNOOZE_OPTIONS[i]);
tv.setOnClickListener(this);
}
}
private void showSnoozeOptions(boolean show) {
mSelectedOption.setVisibility(show ? View.GONE : View.VISIBLE);
mUndo.setVisibility(show ? View.GONE : View.VISIBLE);
mSnoozeOptionView.setVisibility(show ? View.VISIBLE : View.GONE);
}
private void setTimeToSnooze(int optionId) {
long snoozeUntilMillis = Calendar.getInstance().getTimeInMillis();
switch (optionId) {
case R.string.snooze_option_15_min:
snoozeUntilMillis += TimeUnit.MINUTES.toMillis(15);
break;
case R.string.snooze_option_30_min:
snoozeUntilMillis += TimeUnit.MINUTES.toMillis(30);
break;
case R.string.snooze_option_1_hour:
snoozeUntilMillis += TimeUnit.MINUTES.toMillis(60);
break;
}
mTimeToSnooze = snoozeUntilMillis;
final Resources res = getResources();
String selectedString = String.format(
res.getString(R.string.snoozed_for_time), res.getString(optionId));
mSelectedOption.setText(selectedString);
showSnoozeOptions(false);
}
@Override
public void onClick(View v) {
if (mGutsInteractionListener != null) {
mGutsInteractionListener.onInteraction(this);
}
final int id = v.getId();
final Integer tag = (Integer) v.getTag();
if (tag != null) {
// From the option list
setTimeToSnooze(tag);
} else if (id == R.id.snooze_option_default) {
// Show more snooze options
showSnoozeOptions(true);
} else if (id == R.id.undo) {
mTimeToSnooze = -1;
mGutsInteractionListener.closeGuts(this);
}
}
@Override
public View getContentView() {
return this;
}
@Override
public void setStatusBarNotification(StatusBarNotification sbn) {
mSbn = sbn;
}
@Override
public void setInteractionListener(GutsInteractionListener listener) {
mGutsInteractionListener = listener;
}
@Override
public void setSnoozeListener(SnoozeListener listener) {
mSnoozeListener = listener;
}
@Override
public boolean handleCloseControls() {
// When snooze is closed (i.e. there was interaction outside of the notification)
// then we commit the snooze action.
if (mSnoozeListener != null && mTimeToSnooze != -1) {
mSnoozeListener.snoozeNotification(mSbn, mTimeToSnooze);
return true;
}
return false;
}
}