Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 1 | package com.android.systemui.statusbar; |
| 2 | /* |
| 3 | * Copyright (C) 2017 The Android Open Source Project |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License |
| 16 | */ |
| 17 | |
| 18 | import java.util.ArrayList; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 19 | import java.util.List; |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 20 | import java.util.concurrent.TimeUnit; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 21 | |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 22 | import com.android.internal.annotations.VisibleForTesting; |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 23 | import com.android.internal.logging.MetricsLogger; |
| 24 | import com.android.internal.logging.nano.MetricsProto.MetricsEvent; |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 25 | import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; |
| 26 | import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 27 | |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 28 | import android.animation.Animator; |
| 29 | import android.animation.AnimatorListenerAdapter; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 30 | import android.animation.AnimatorSet; |
| 31 | import android.animation.ObjectAnimator; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 32 | import android.content.Context; |
| 33 | import android.content.res.Resources; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 34 | import android.graphics.Typeface; |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 35 | import android.metrics.LogMaker; |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 36 | import android.os.Bundle; |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 37 | import android.provider.Settings; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 38 | import android.service.notification.SnoozeCriterion; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 39 | import android.service.notification.StatusBarNotification; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 40 | import android.text.SpannableString; |
| 41 | import android.text.style.StyleSpan; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 42 | import android.util.AttributeSet; |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 43 | import android.util.KeyValueListParser; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 44 | import android.util.Log; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 45 | import android.view.LayoutInflater; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 46 | import android.view.View; |
| 47 | import android.view.ViewGroup; |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 48 | import android.view.accessibility.AccessibilityEvent; |
| 49 | import android.view.accessibility.AccessibilityNodeInfo; |
| 50 | import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 51 | import android.widget.ImageView; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 52 | import android.widget.LinearLayout; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 53 | import android.widget.TextView; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 54 | |
| 55 | import com.android.systemui.Interpolators; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 56 | import com.android.systemui.R; |
| 57 | |
| 58 | public class NotificationSnooze extends LinearLayout |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 59 | implements NotificationGuts.GutsContent, View.OnClickListener { |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 60 | |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 61 | private static final String TAG = "NotificationSnooze"; |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 62 | /** |
| 63 | * If this changes more number increases, more assistant action resId's should be defined for |
| 64 | * accessibility purposes, see {@link #setSnoozeOptions(List)} |
| 65 | */ |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 66 | private static final int MAX_ASSISTANT_SUGGESTIONS = 1; |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 67 | private static final String KEY_DEFAULT_SNOOZE = "default"; |
| 68 | private static final String KEY_OPTIONS = "options_array"; |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 69 | private static final LogMaker OPTIONS_OPEN_LOG = |
| 70 | new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS) |
| 71 | .setType(MetricsEvent.TYPE_OPEN); |
| 72 | private static final LogMaker OPTIONS_CLOSE_LOG = |
| 73 | new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS) |
| 74 | .setType(MetricsEvent.TYPE_CLOSE); |
| 75 | private static final LogMaker UNDO_LOG = |
| 76 | new LogMaker(MetricsEvent.NOTIFICATION_UNDO_SNOOZE) |
| 77 | .setType(MetricsEvent.TYPE_ACTION); |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 78 | private NotificationGuts mGutsContainer; |
| 79 | private NotificationSwipeActionHelper mSnoozeListener; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 80 | private StatusBarNotification mSbn; |
| 81 | |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 82 | private TextView mSelectedOptionText; |
| 83 | private TextView mUndoButton; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 84 | private ImageView mExpandButton; |
| 85 | private View mDivider; |
| 86 | private ViewGroup mSnoozeOptionContainer; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 87 | private List<SnoozeOption> mSnoozeOptions; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 88 | private int mCollapsedHeight; |
Mady Mellor | 651fbde | 2017-05-18 14:02:51 -0700 | [diff] [blame] | 89 | private SnoozeOption mDefaultOption; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 90 | private SnoozeOption mSelectedOption; |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 91 | private boolean mSnoozing; |
| 92 | private boolean mExpanded; |
| 93 | private AnimatorSet mExpandAnimation; |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 94 | private KeyValueListParser mParser; |
| 95 | |
| 96 | private final static int[] sAccessibilityActions = { |
| 97 | R.id.action_snooze_shorter, |
| 98 | R.id.action_snooze_short, |
| 99 | R.id.action_snooze_long, |
| 100 | R.id.action_snooze_longer, |
| 101 | }; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 102 | |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 103 | private MetricsLogger mMetricsLogger = new MetricsLogger(); |
| 104 | |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 105 | public NotificationSnooze(Context context, AttributeSet attrs) { |
| 106 | super(context, attrs); |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 107 | mParser = new KeyValueListParser(','); |
| 108 | } |
| 109 | |
| 110 | @VisibleForTesting |
| 111 | SnoozeOption getDefaultOption() |
| 112 | { |
| 113 | return mDefaultOption; |
| 114 | } |
| 115 | |
| 116 | @VisibleForTesting |
| 117 | void setKeyValueListParser(KeyValueListParser parser) { |
| 118 | mParser = parser; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | @Override |
| 122 | protected void onFinishInflate() { |
| 123 | super.onFinishInflate(); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 124 | mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.snooze_snackbar_min_height); |
| 125 | findViewById(R.id.notification_snooze).setOnClickListener(this); |
| 126 | mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default); |
| 127 | mUndoButton = (TextView) findViewById(R.id.undo); |
| 128 | mUndoButton.setOnClickListener(this); |
| 129 | mExpandButton = (ImageView) findViewById(R.id.expand_button); |
| 130 | mDivider = findViewById(R.id.divider); |
| 131 | mDivider.setAlpha(0f); |
| 132 | mSnoozeOptionContainer = (ViewGroup) findViewById(R.id.snooze_options); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 133 | mSnoozeOptionContainer.setVisibility(View.INVISIBLE); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 134 | mSnoozeOptionContainer.setAlpha(0f); |
| 135 | |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 136 | // Create the different options based on list |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 137 | mSnoozeOptions = getDefaultSnoozeOptions(); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 138 | createOptionViews(); |
| 139 | |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 140 | setSelected(mDefaultOption, false); |
| 141 | } |
| 142 | |
| 143 | @Override |
| 144 | protected void onAttachedToWindow() { |
| 145 | super.onAttachedToWindow(); |
| 146 | logOptionSelection(MetricsEvent.NOTIFICATION_SNOOZE_CLICKED, mDefaultOption); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 147 | } |
| 148 | |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 149 | @Override |
| 150 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) { |
| 151 | super.onInitializeAccessibilityEvent(event); |
| 152 | if (mGutsContainer != null && mGutsContainer.isExposed()) { |
| 153 | if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { |
| 154 | event.getText().add(mSelectedOptionText.getText()); |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | @Override |
| 160 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { |
| 161 | super.onInitializeAccessibilityNodeInfo(info); |
| 162 | info.addAction(new AccessibilityAction(R.id.action_snooze_undo, |
| 163 | getResources().getString(R.string.snooze_undo))); |
| 164 | int count = mSnoozeOptions.size(); |
| 165 | for (int i = 0; i < count; i++) { |
| 166 | AccessibilityAction action = mSnoozeOptions.get(i).getAccessibilityAction(); |
| 167 | if (action != null) { |
| 168 | info.addAction(action); |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | @Override |
| 174 | public boolean performAccessibilityActionInternal(int action, Bundle arguments) { |
| 175 | if (super.performAccessibilityActionInternal(action, arguments)) { |
| 176 | return true; |
| 177 | } |
| 178 | if (action == R.id.action_snooze_undo) { |
| 179 | undoSnooze(mUndoButton); |
| 180 | return true; |
| 181 | } |
| 182 | for (int i = 0; i < mSnoozeOptions.size(); i++) { |
| 183 | SnoozeOption so = mSnoozeOptions.get(i); |
| 184 | if (so.getAccessibilityAction() != null |
| 185 | && so.getAccessibilityAction().getId() == action) { |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 186 | setSelected(so, true); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 187 | return true; |
| 188 | } |
| 189 | } |
| 190 | return false; |
| 191 | } |
| 192 | |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 193 | public void setSnoozeOptions(final List<SnoozeCriterion> snoozeList) { |
| 194 | if (snoozeList == null) { |
| 195 | return; |
| 196 | } |
| 197 | mSnoozeOptions.clear(); |
| 198 | mSnoozeOptions = getDefaultSnoozeOptions(); |
| 199 | final int count = Math.min(MAX_ASSISTANT_SUGGESTIONS, snoozeList.size()); |
| 200 | for (int i = 0; i < count; i++) { |
| 201 | SnoozeCriterion sc = snoozeList.get(i); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 202 | AccessibilityAction action = new AccessibilityAction( |
| 203 | R.id.action_snooze_assistant_suggestion_1, sc.getExplanation()); |
| 204 | mSnoozeOptions.add(new NotificationSnoozeOption(sc, 0, sc.getExplanation(), |
| 205 | sc.getConfirmation(), action)); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 206 | } |
| 207 | createOptionViews(); |
| 208 | } |
| 209 | |
Mady Mellor | c2dbe49 | 2017-03-30 13:22:03 -0700 | [diff] [blame] | 210 | public boolean isExpanded() { |
| 211 | return mExpanded; |
| 212 | } |
| 213 | |
| 214 | public void setSnoozeListener(NotificationSwipeActionHelper listener) { |
| 215 | mSnoozeListener = listener; |
| 216 | } |
| 217 | |
| 218 | public void setStatusBarNotification(StatusBarNotification sbn) { |
| 219 | mSbn = sbn; |
| 220 | } |
| 221 | |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 222 | @VisibleForTesting |
| 223 | ArrayList<SnoozeOption> getDefaultSnoozeOptions() { |
| 224 | final Resources resources = getContext().getResources(); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 225 | ArrayList<SnoozeOption> options = new ArrayList<>(); |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 226 | try { |
| 227 | final String config = Settings.Global.getString(getContext().getContentResolver(), |
| 228 | Settings.Global.NOTIFICATION_SNOOZE_OPTIONS); |
| 229 | mParser.setString(config); |
| 230 | } catch (IllegalArgumentException e) { |
| 231 | Log.e(TAG, "Bad snooze constants"); |
| 232 | } |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 233 | |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 234 | final int defaultSnooze = mParser.getInt(KEY_DEFAULT_SNOOZE, |
| 235 | resources.getInteger(R.integer.config_notification_snooze_time_default)); |
Chris Wren | 4170751 | 2017-12-06 00:12:17 -0500 | [diff] [blame] | 236 | final int[] snoozeTimes = mParser.getIntArray(KEY_OPTIONS, |
Chris Wren | e901a7e | 2017-10-02 17:29:46 -0400 | [diff] [blame] | 237 | resources.getIntArray(R.array.config_notification_snooze_times)); |
| 238 | |
| 239 | for (int i = 0; i < snoozeTimes.length && i < sAccessibilityActions.length; i++) { |
| 240 | int snoozeTime = snoozeTimes[i]; |
| 241 | SnoozeOption option = createOption(snoozeTime, sAccessibilityActions[i]); |
| 242 | if (i == 0 || snoozeTime == defaultSnooze) { |
| 243 | mDefaultOption = option; |
| 244 | } |
| 245 | options.add(option); |
| 246 | } |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 247 | return options; |
| 248 | } |
| 249 | |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 250 | private SnoozeOption createOption(int minutes, int accessibilityActionId) { |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 251 | Resources res = getResources(); |
Mady Mellor | 6143b90 | 2017-05-10 17:16:28 -0700 | [diff] [blame] | 252 | boolean showInHours = minutes >= 60; |
| 253 | int pluralResId = showInHours |
| 254 | ? R.plurals.snoozeHourOptions |
| 255 | : R.plurals.snoozeMinuteOptions; |
| 256 | int count = showInHours ? (minutes / 60) : minutes; |
| 257 | String description = res.getQuantityString(pluralResId, count, count); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 258 | String resultText = String.format(res.getString(R.string.snoozed_for_time), description); |
| 259 | SpannableString string = new SpannableString(resultText); |
| 260 | string.setSpan(new StyleSpan(Typeface.BOLD), |
| 261 | resultText.length() - description.length(), resultText.length(), 0 /* flags */); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 262 | AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description); |
| 263 | return new NotificationSnoozeOption(null, minutes, description, string, |
| 264 | action); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 265 | } |
| 266 | |
| 267 | private void createOptionViews() { |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 268 | mSnoozeOptionContainer.removeAllViews(); |
| 269 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( |
| 270 | Context.LAYOUT_INFLATER_SERVICE); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 271 | for (int i = 0; i < mSnoozeOptions.size(); i++) { |
| 272 | SnoozeOption option = mSnoozeOptions.get(i); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 273 | TextView tv = (TextView) inflater.inflate(R.layout.notification_snooze_option, |
| 274 | mSnoozeOptionContainer, false); |
| 275 | mSnoozeOptionContainer.addView(tv); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 276 | tv.setText(option.getDescription()); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 277 | tv.setTag(option); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 278 | tv.setOnClickListener(this); |
| 279 | } |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 280 | } |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 281 | |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 282 | private void hideSelectedOption() { |
| 283 | final int childCount = mSnoozeOptionContainer.getChildCount(); |
| 284 | for (int i = 0; i < childCount; i++) { |
| 285 | final View child = mSnoozeOptionContainer.getChildAt(i); |
| 286 | child.setVisibility(child.getTag() == mSelectedOption ? View.GONE : View.VISIBLE); |
| 287 | } |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | private void showSnoozeOptions(boolean show) { |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 291 | int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification |
| 292 | : com.android.internal.R.drawable.ic_expand_notification; |
| 293 | mExpandButton.setImageResource(drawableId); |
Selim Cinek | e8ea7f6 | 2017-04-28 19:22:17 -0700 | [diff] [blame] | 294 | if (mExpanded != show) { |
| 295 | mExpanded = show; |
| 296 | animateSnoozeOptions(show); |
| 297 | if (mGutsContainer != null) { |
| 298 | mGutsContainer.onHeightChanged(); |
| 299 | } |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 300 | } |
| 301 | } |
| 302 | |
| 303 | private void animateSnoozeOptions(boolean show) { |
| 304 | if (mExpandAnimation != null) { |
| 305 | mExpandAnimation.cancel(); |
| 306 | } |
| 307 | ObjectAnimator dividerAnim = ObjectAnimator.ofFloat(mDivider, View.ALPHA, |
| 308 | mDivider.getAlpha(), show ? 1f : 0f); |
| 309 | ObjectAnimator optionAnim = ObjectAnimator.ofFloat(mSnoozeOptionContainer, View.ALPHA, |
| 310 | mSnoozeOptionContainer.getAlpha(), show ? 1f : 0f); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 311 | mSnoozeOptionContainer.setVisibility(View.VISIBLE); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 312 | mExpandAnimation = new AnimatorSet(); |
| 313 | mExpandAnimation.playTogether(dividerAnim, optionAnim); |
| 314 | mExpandAnimation.setDuration(150); |
| 315 | mExpandAnimation.setInterpolator(show ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 316 | mExpandAnimation.addListener(new AnimatorListenerAdapter() { |
| 317 | boolean cancelled = false; |
| 318 | |
| 319 | @Override |
| 320 | public void onAnimationCancel(Animator animation) { |
| 321 | cancelled = true; |
| 322 | } |
| 323 | |
| 324 | @Override |
| 325 | public void onAnimationEnd(Animator animation) { |
| 326 | if (!show && !cancelled) { |
| 327 | mSnoozeOptionContainer.setVisibility(View.INVISIBLE); |
| 328 | mSnoozeOptionContainer.setAlpha(0f); |
| 329 | } |
| 330 | } |
| 331 | }); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 332 | mExpandAnimation.start(); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 333 | } |
| 334 | |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 335 | private void setSelected(SnoozeOption option, boolean userAction) { |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 336 | mSelectedOption = option; |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 337 | mSelectedOptionText.setText(option.getConfirmation()); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 338 | showSnoozeOptions(false); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 339 | hideSelectedOption(); |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 340 | sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 341 | if (userAction) { |
| 342 | logOptionSelection(MetricsEvent.NOTIFICATION_SELECT_SNOOZE, option); |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | private void logOptionSelection(int category, SnoozeOption option) { |
| 347 | int index = mSnoozeOptions.indexOf(option); |
| 348 | long duration = TimeUnit.MINUTES.toMillis(option.getMinutesToSnoozeFor()); |
| 349 | mMetricsLogger.write(new LogMaker(category) |
| 350 | .setType(MetricsEvent.TYPE_ACTION) |
| 351 | .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_INDEX, index) |
| 352 | .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, duration)); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 353 | } |
| 354 | |
| 355 | @Override |
| 356 | public void onClick(View v) { |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 357 | if (mGutsContainer != null) { |
| 358 | mGutsContainer.resetFalsingCheck(); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 359 | } |
| 360 | final int id = v.getId(); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 361 | final SnoozeOption tag = (SnoozeOption) v.getTag(); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 362 | if (tag != null) { |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 363 | setSelected(tag, true); |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 364 | } else if (id == R.id.notification_snooze) { |
| 365 | // Toggle snooze options |
| 366 | showSnoozeOptions(!mExpanded); |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 367 | mMetricsLogger.write(!mExpanded ? OPTIONS_OPEN_LOG : OPTIONS_CLOSE_LOG); |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 368 | } else { |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 369 | // Undo snooze was selected |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 370 | undoSnooze(v); |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 371 | mMetricsLogger.write(UNDO_LOG); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 372 | } |
| 373 | } |
| 374 | |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 375 | private void undoSnooze(View v) { |
| 376 | mSelectedOption = null; |
| 377 | int[] parentLoc = new int[2]; |
| 378 | int[] targetLoc = new int[2]; |
| 379 | mGutsContainer.getLocationOnScreen(parentLoc); |
| 380 | v.getLocationOnScreen(targetLoc); |
| 381 | final int centerX = v.getWidth() / 2; |
| 382 | final int centerY = v.getHeight() / 2; |
| 383 | final int x = targetLoc[0] - parentLoc[0] + centerX; |
| 384 | final int y = targetLoc[1] - parentLoc[1] + centerY; |
| 385 | showSnoozeOptions(false); |
| 386 | mGutsContainer.closeControls(x, y, false /* save */, false /* force */); |
| 387 | } |
| 388 | |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 389 | @Override |
| 390 | public int getActualHeight() { |
| 391 | return mExpanded ? getHeight() : mCollapsedHeight; |
Mady Mellor | 754d822 | 2017-01-25 15:29:39 -0800 | [diff] [blame] | 392 | } |
| 393 | |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 394 | @Override |
Mady Mellor | 434180c | 2017-02-13 11:29:42 -0800 | [diff] [blame] | 395 | public boolean willBeRemoved() { |
| 396 | return mSnoozing; |
| 397 | } |
| 398 | |
| 399 | @Override |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 400 | public View getContentView() { |
Mady Mellor | e09fb70 | 2017-03-30 13:23:29 -0700 | [diff] [blame] | 401 | // Reset the view before use |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 402 | setSelected(mDefaultOption, false); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 403 | return this; |
| 404 | } |
| 405 | |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 406 | @Override |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 407 | public void setGutsParent(NotificationGuts guts) { |
| 408 | mGutsContainer = guts; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 409 | } |
| 410 | |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 411 | @Override |
Mady Mellor | c2dbe49 | 2017-03-30 13:22:03 -0700 | [diff] [blame] | 412 | public boolean handleCloseControls(boolean save, boolean force) { |
| 413 | if (mExpanded && !force) { |
| 414 | // Collapse expanded state on outside touch |
| 415 | showSnoozeOptions(false); |
| 416 | return true; |
| 417 | } else if (mSnoozeListener != null && mSelectedOption != null) { |
| 418 | // Snooze option selected so commit it |
Mady Mellor | 434180c | 2017-02-13 11:29:42 -0800 | [diff] [blame] | 419 | mSnoozing = true; |
Mady Mellor | 95d743c | 2017-01-10 12:05:27 -0800 | [diff] [blame] | 420 | mSnoozeListener.snooze(mSbn, mSelectedOption); |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 421 | return true; |
Mady Mellor | c2dbe49 | 2017-03-30 13:22:03 -0700 | [diff] [blame] | 422 | } else { |
| 423 | // The view should actually be closed |
Chris Wren | 21a2e72 | 2017-10-02 17:44:53 -0400 | [diff] [blame] | 424 | setSelected(mSnoozeOptions.get(0), false); |
Mady Mellor | c2dbe49 | 2017-03-30 13:22:03 -0700 | [diff] [blame] | 425 | return false; // Return false here so that guts handles closing the view |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 426 | } |
Mady Mellor | c2dbe49 | 2017-03-30 13:22:03 -0700 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | @Override |
| 430 | public boolean isLeavebehind() { |
| 431 | return true; |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 432 | } |
Mady Mellor | 920fd89 | 2017-06-06 09:35:03 -0700 | [diff] [blame] | 433 | |
| 434 | public class NotificationSnoozeOption implements SnoozeOption { |
| 435 | private SnoozeCriterion mCriterion; |
| 436 | private int mMinutesToSnoozeFor; |
| 437 | private CharSequence mDescription; |
| 438 | private CharSequence mConfirmation; |
| 439 | private AccessibilityAction mAction; |
| 440 | |
| 441 | public NotificationSnoozeOption(SnoozeCriterion sc, int minToSnoozeFor, |
| 442 | CharSequence description, |
| 443 | CharSequence confirmation, AccessibilityAction action) { |
| 444 | mCriterion = sc; |
| 445 | mMinutesToSnoozeFor = minToSnoozeFor; |
| 446 | mDescription = description; |
| 447 | mConfirmation = confirmation; |
| 448 | mAction = action; |
| 449 | } |
| 450 | |
| 451 | @Override |
| 452 | public SnoozeCriterion getSnoozeCriterion() { |
| 453 | return mCriterion; |
| 454 | } |
| 455 | |
| 456 | @Override |
| 457 | public CharSequence getDescription() { |
| 458 | return mDescription; |
| 459 | } |
| 460 | |
| 461 | @Override |
| 462 | public CharSequence getConfirmation() { |
| 463 | return mConfirmation; |
| 464 | } |
| 465 | |
| 466 | @Override |
| 467 | public int getMinutesToSnoozeFor() { |
| 468 | return mMinutesToSnoozeFor; |
| 469 | } |
| 470 | |
| 471 | @Override |
| 472 | public AccessibilityAction getAccessibilityAction() { |
| 473 | return mAction; |
| 474 | } |
| 475 | |
| 476 | } |
Mady Mellor | 04d7a0f | 2017-01-25 13:16:03 -0800 | [diff] [blame] | 477 | } |