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:
12
packages/SystemUI/res/drawable/ic_snooze.xml
Normal file
12
packages/SystemUI/res/drawable/ic_snooze.xml
Normal 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>
|
||||
65
packages/SystemUI/res/layout/notification_snooze.xml
Normal file
65
packages/SystemUI/res/layout/notification_snooze.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user