blob: b1ad30c940fb554ad14c62ca1f59fb5291712971 [file] [log] [blame]
Mady Mellor87d79452017-01-10 11:52:52 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050017package com.android.systemui.statusbar;
18
Julia Reynoldse0341482018-03-08 14:42:50 -050019import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds3aedded2017-03-31 14:42:09 -040020import static android.app.NotificationManager.IMPORTANCE_NONE;
21
Julia Reynolds437cdb12018-01-03 12:27:24 -050022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
24import android.animation.AnimatorSet;
25import android.animation.ObjectAnimator;
Mady Mellor87d79452017-01-10 11:52:52 -080026import android.app.INotificationManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040027import android.app.Notification;
Mady Mellor87d79452017-01-10 11:52:52 -080028import android.app.NotificationChannel;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050029import android.app.NotificationChannelGroup;
Mady Mellor87d79452017-01-10 11:52:52 -080030import android.content.Context;
Julia Reynolds3aedded2017-03-31 14:42:09 -040031import android.content.Intent;
32import android.content.pm.ActivityInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080033import android.content.pm.ApplicationInfo;
34import android.content.pm.PackageInfo;
35import android.content.pm.PackageManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040036import android.content.pm.ResolveInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080037import android.graphics.drawable.Drawable;
Mady Mellor87d79452017-01-10 11:52:52 -080038import android.os.RemoteException;
Julia Reynolds3aedded2017-03-31 14:42:09 -040039import android.service.notification.StatusBarNotification;
40import android.text.TextUtils;
Mady Mellor87d79452017-01-10 11:52:52 -080041import android.util.AttributeSet;
Mady Mellor87d79452017-01-10 11:52:52 -080042import android.view.View;
Julia Reynoldse0341482018-03-08 14:42:50 -050043import android.view.ViewGroup;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -040044import android.view.accessibility.AccessibilityEvent;
Mady Mellor87d79452017-01-10 11:52:52 -080045import android.widget.ImageView;
46import android.widget.LinearLayout;
Mady Mellor87d79452017-01-10 11:52:52 -080047import android.widget.TextView;
48
49import com.android.internal.logging.MetricsLogger;
50import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
51import com.android.settingslib.Utils;
Julia Reynolds437cdb12018-01-03 12:27:24 -050052import com.android.systemui.Interpolators;
Mady Mellor87d79452017-01-10 11:52:52 -080053import com.android.systemui.R;
Mady Mellor87d79452017-01-10 11:52:52 -080054
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050055import java.util.List;
Mady Mellor87d79452017-01-10 11:52:52 -080056import java.util.Set;
57
58/**
59 * The guts of a notification revealed when performing a long press.
60 */
Mady Mellor95d743c2017-01-10 12:05:27 -080061public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
Mady Mellor87d79452017-01-10 11:52:52 -080062 private static final String TAG = "InfoGuts";
63
64 private INotificationManager mINotificationManager;
Julia Reynolds437cdb12018-01-03 12:27:24 -050065 private PackageManager mPm;
66
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050067 private String mPkg;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -040068 private String mAppName;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050069 private int mAppUid;
Julia Reynolds437cdb12018-01-03 12:27:24 -050070 private int mNumNotificationChannels;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050071 private NotificationChannel mSingleNotificationChannel;
Mady Mellor87d79452017-01-10 11:52:52 -080072 private int mStartingUserImportance;
Julia Reynolds437cdb12018-01-03 12:27:24 -050073 private int mChosenImportance;
74 private boolean mIsSingleDefaultChannel;
75 private boolean mNonblockable;
76 private StatusBarNotification mSbn;
77 private AnimatorSet mExpandAnimation;
Julia Reynoldse0341482018-03-08 14:42:50 -050078 private boolean mIsForeground;
Mady Mellor87d79452017-01-10 11:52:52 -080079
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -040080 private CheckSaveListener mCheckSaveListener;
Julia Reynolds437cdb12018-01-03 12:27:24 -050081 private OnSettingsClickListener mOnSettingsClickListener;
Julia Reynolds3aedded2017-03-31 14:42:09 -040082 private OnAppSettingsClickListener mAppSettingsClickListener;
Mady Mellor95d743c2017-01-10 12:05:27 -080083 private NotificationGuts mGutsContainer;
Julia Reynolds0ef7d842018-01-24 17:50:31 -050084 private boolean mNegativeUserSentiment;
Mady Mellor87d79452017-01-10 11:52:52 -080085
Julia Reynolds437cdb12018-01-03 12:27:24 -050086 private OnClickListener mOnKeepShowing = v -> {
87 closeControls(v);
88 };
89
Julia Reynoldse0341482018-03-08 14:42:50 -050090 private OnClickListener mOnStopMinNotifications = v -> {
Julia Reynolds437cdb12018-01-03 12:27:24 -050091 swapContent(false);
92 };
93
94 private OnClickListener mOnUndo = v -> {
95 swapContent(true);
96 };
97
Mady Mellor87d79452017-01-10 11:52:52 -080098 public NotificationInfo(Context context, AttributeSet attrs) {
99 super(context, attrs);
100 }
101
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400102 // Specify a CheckSaveListener to override when/if the user's changes are committed.
103 public interface CheckSaveListener {
104 // Invoked when importance has changed and the NotificationInfo wants to try to save it.
105 // Listener should run saveImportance unless the change should be canceled.
Eliot Courtney47098cb2017-10-18 17:30:30 +0900106 void checkSave(Runnable saveImportance, StatusBarNotification sbn);
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400107 }
108
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500109 public interface OnSettingsClickListener {
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500110 void onClick(View v, NotificationChannel channel, int appUid);
Mady Mellor87d79452017-01-10 11:52:52 -0800111 }
112
Julia Reynolds3aedded2017-03-31 14:42:09 -0400113 public interface OnAppSettingsClickListener {
114 void onClick(View v, Intent intent);
115 }
116
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500117 public void bindNotification(final PackageManager pm,
118 final INotificationManager iNotificationManager,
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500119 final String pkg,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500120 final NotificationChannel notificationChannel,
121 final int numChannels,
Julia Reynolds3aedded2017-03-31 14:42:09 -0400122 final StatusBarNotification sbn,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500123 final CheckSaveListener checkSaveListener,
124 final OnSettingsClickListener onSettingsClick,
125 final OnAppSettingsClickListener onAppSettingsClick,
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400126 final Set<String> nonBlockablePkgs)
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500127 throws RemoteException {
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500128 bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
129 checkSaveListener, onSettingsClick, onAppSettingsClick, nonBlockablePkgs,
130 false /* negative sentiment */);
131 }
132
133 public void bindNotification(final PackageManager pm,
134 final INotificationManager iNotificationManager,
135 final String pkg,
136 final NotificationChannel notificationChannel,
137 final int numChannels,
138 final StatusBarNotification sbn,
139 final CheckSaveListener checkSaveListener,
140 final OnSettingsClickListener onSettingsClick,
141 final OnAppSettingsClickListener onAppSettingsClick,
142 final Set<String> nonBlockablePkgs,
143 boolean negativeUserSentiment) throws RemoteException {
Mady Mellor87d79452017-01-10 11:52:52 -0800144 mINotificationManager = iNotificationManager;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500145 mPkg = pkg;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500146 mNumNotificationChannels = numChannels;
Julia Reynolds3aedded2017-03-31 14:42:09 -0400147 mSbn = sbn;
148 mPm = pm;
149 mAppSettingsClickListener = onAppSettingsClick;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400150 mAppName = mPkg;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500151 mCheckSaveListener = checkSaveListener;
152 mOnSettingsClickListener = onSettingsClick;
153 mSingleNotificationChannel = notificationChannel;
154 mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500155 mNegativeUserSentiment = negativeUserSentiment;
Julia Reynoldse0341482018-03-08 14:42:50 -0500156 mIsForeground =
157 (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500158
Julia Reynolds437cdb12018-01-03 12:27:24 -0500159 int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400160 pkg, mAppUid, false /* includeDeleted */);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500161 if (mNumNotificationChannels == 0) {
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400162 throw new IllegalArgumentException("bindNotification requires at least one channel");
163 } else {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500164 // Special behavior for the Default channel if no other channels have been defined.
165 mIsSingleDefaultChannel = mNumNotificationChannels == 1
166 && mSingleNotificationChannel.getId()
167 .equals(NotificationChannel.DEFAULT_CHANNEL_ID)
168 && numTotalChannels <= 1;
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400169 }
170
Geoffrey Pitschb43486a2017-06-01 13:45:59 -0400171 try {
172 final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
173 if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500174 if (mSingleNotificationChannel != null
175 && !mSingleNotificationChannel.isBlockableSystem()) {
176 mNonblockable = true;
Geoffrey Pitschb43486a2017-06-01 13:45:59 -0400177 }
178 }
179 } catch (PackageManager.NameNotFoundException e) {
180 // unlikely.
181 }
182 if (nonBlockablePkgs != null) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500183 mNonblockable |= nonBlockablePkgs.contains(pkg);
Geoffrey Pitschb43486a2017-06-01 13:45:59 -0400184 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500185 mNonblockable |= (mNumNotificationChannels > 1);
Geoffrey Pitschb43486a2017-06-01 13:45:59 -0400186
Julia Reynolds437cdb12018-01-03 12:27:24 -0500187 bindHeader();
188 bindPrompt();
189 bindButtons();
190 }
191
192 private void bindHeader() throws RemoteException {
193 // Package name
194 Drawable pkgicon = null;
195 ApplicationInfo info;
196 try {
197 info = mPm.getApplicationInfo(mPkg,
198 PackageManager.MATCH_UNINSTALLED_PACKAGES
199 | PackageManager.MATCH_DISABLED_COMPONENTS
200 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
201 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
202 if (info != null) {
203 mAppUid = mSbn.getUid();
204 mAppName = String.valueOf(mPm.getApplicationLabel(info));
205 pkgicon = mPm.getApplicationIcon(info);
Geoffrey Pitschee8c81e2017-03-23 11:38:56 -0400206 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500207 } catch (PackageManager.NameNotFoundException e) {
208 // app is gone, just show package name and generic icon
209 pkgicon = mPm.getDefaultActivityIcon();
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500210 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500211 ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400212 ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
Mady Mellor87d79452017-01-10 11:52:52 -0800213
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500214 // Set group information if this channel has an associated group.
215 CharSequence groupName = null;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500216 if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
217 final NotificationChannelGroup notificationChannelGroup =
Julia Reynolds437cdb12018-01-03 12:27:24 -0500218 mINotificationManager.getNotificationChannelGroupForPackage(
219 mSingleNotificationChannel.getGroup(), mPkg, mAppUid);
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500220 if (notificationChannelGroup != null) {
221 groupName = notificationChannelGroup.getName();
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500222 }
Mady Mellor87d79452017-01-10 11:52:52 -0800223 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500224 TextView groupNameView = findViewById(R.id.group_name);
225 TextView groupDividerView = findViewById(R.id.pkg_group_divider);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500226 if (groupName != null) {
227 groupNameView.setText(groupName);
228 groupNameView.setVisibility(View.VISIBLE);
229 groupDividerView.setVisibility(View.VISIBLE);
230 } else {
231 groupNameView.setVisibility(View.GONE);
232 groupDividerView.setVisibility(View.GONE);
233 }
Mady Mellor87d79452017-01-10 11:52:52 -0800234
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500235 // Settings button.
Julia Reynolds437cdb12018-01-03 12:27:24 -0500236 final View settingsButton = findViewById(R.id.info);
237 if (mAppUid >= 0 && mOnSettingsClickListener != null) {
Geoffrey Pitsch029a3fa2017-03-30 13:01:57 -0400238 settingsButton.setVisibility(View.VISIBLE);
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500239 final int appUidF = mAppUid;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500240 settingsButton.setOnClickListener(
241 (View view) -> {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500242 mOnSettingsClickListener.onClick(view,
243 mNumNotificationChannels > 1 ? null : mSingleNotificationChannel,
244 appUidF);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500245 });
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500246 } else {
247 settingsButton.setVisibility(View.GONE);
248 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500249 }
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500250
Julia Reynolds437cdb12018-01-03 12:27:24 -0500251 private void bindPrompt() {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500252 final TextView blockPrompt = findViewById(R.id.block_prompt);
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500253 bindName();
Julia Reynolds437cdb12018-01-03 12:27:24 -0500254 if (mNonblockable) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500255 blockPrompt.setText(R.string.notification_unblockable_desc);
256 } else {
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500257 if (mNegativeUserSentiment) {
258 blockPrompt.setText(R.string.inline_blocking_helper);
259 } else if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500260 blockPrompt.setText(R.string.inline_keep_showing_app);
261 } else {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500262 blockPrompt.setText(R.string.inline_keep_showing);
263 }
264 }
Mady Mellor87d79452017-01-10 11:52:52 -0800265 }
266
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500267 private void bindName() {
268 final TextView channelName = findViewById(R.id.channel_name);
269 if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
270 channelName.setVisibility(View.GONE);
271 } else {
272 channelName.setText(mSingleNotificationChannel.getName());
273 }
274 }
275
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400276 private boolean hasImportanceChanged() {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500277 return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
Mady Mellor87d79452017-01-10 11:52:52 -0800278 }
279
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500280 private void saveImportance() {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500281 if (mNonblockable) {
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500282 return;
283 }
Mady Mellor87d79452017-01-10 11:52:52 -0800284 MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500285 mChosenImportance - mStartingUserImportance);
286 mSingleNotificationChannel.setImportance(mChosenImportance);
Julia Reynolds8ceb5792017-04-11 11:32:44 -0400287 mSingleNotificationChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
Mady Mellor87d79452017-01-10 11:52:52 -0800288 try {
289 mINotificationManager.updateNotificationChannelForPackage(
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500290 mPkg, mAppUid, mSingleNotificationChannel);
Mady Mellor87d79452017-01-10 11:52:52 -0800291 } catch (RemoteException e) {
292 // :(
293 }
294 }
295
Julia Reynolds437cdb12018-01-03 12:27:24 -0500296 private void bindButtons() {
297 View block = findViewById(R.id.block);
Julia Reynoldse0341482018-03-08 14:42:50 -0500298 block.setOnClickListener(mOnStopMinNotifications);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500299 TextView keep = findViewById(R.id.keep);
300 keep.setOnClickListener(mOnKeepShowing);
301 findViewById(R.id.undo).setOnClickListener(mOnUndo);
Julia Reynoldse0341482018-03-08 14:42:50 -0500302 View minimize = findViewById(R.id.minimize);
303 minimize.setOnClickListener(mOnStopMinNotifications);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500304
305 if (mNonblockable) {
306 keep.setText(R.string.notification_done);
307 block.setVisibility(GONE);
Julia Reynoldse0341482018-03-08 14:42:50 -0500308 minimize.setVisibility(GONE);
309 } else if (mIsForeground) {
310 block.setVisibility(GONE);
311 minimize.setVisibility(VISIBLE);
312 } else if (!mIsForeground) {
313 block.setVisibility(VISIBLE);
314 minimize.setVisibility(GONE);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500315 }
316
317 // app settings link
318 TextView settingsLinkView = findViewById(R.id.app_settings);
319 Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
320 mSbn.getId(), mSbn.getTag());
321 if (settingsIntent != null
322 && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
Julia Reynoldse0341482018-03-08 14:42:50 -0500323 settingsLinkView.setVisibility(VISIBLE);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500324 settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
325 mSbn.getNotification().getSettingsText()));
326 settingsLinkView.setOnClickListener((View view) -> {
327 mAppSettingsClickListener.onClick(view, settingsIntent);
328 });
Mady Mellor87d79452017-01-10 11:52:52 -0800329 } else {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500330 settingsLinkView.setVisibility(View.GONE);
Mady Mellor87d79452017-01-10 11:52:52 -0800331 }
332 }
333
Julia Reynolds437cdb12018-01-03 12:27:24 -0500334 private void swapContent(boolean showPrompt) {
335 if (mExpandAnimation != null) {
336 mExpandAnimation.cancel();
337 }
Mady Mellor87d79452017-01-10 11:52:52 -0800338
Julia Reynoldse0341482018-03-08 14:42:50 -0500339 View prompt = findViewById(R.id.prompt);
340 ViewGroup confirmation = findViewById(R.id.confirmation);
341 TextView confirmationText = findViewById(R.id.confirmation_text);
342 View header = findViewById(R.id.header);
343
Julia Reynolds437cdb12018-01-03 12:27:24 -0500344 if (showPrompt) {
345 mChosenImportance = mStartingUserImportance;
Julia Reynoldse0341482018-03-08 14:42:50 -0500346 } else if (mIsForeground) {
347 mChosenImportance = IMPORTANCE_MIN;
348 confirmationText.setText(R.string.notification_channel_minimized);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500349 } else {
350 mChosenImportance = IMPORTANCE_NONE;
Julia Reynoldse0341482018-03-08 14:42:50 -0500351 confirmationText.setText(R.string.notification_channel_disabled);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500352 }
353
Julia Reynolds437cdb12018-01-03 12:27:24 -0500354 ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
355 prompt.getAlpha(), showPrompt ? 1f : 0f);
356 promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
357 ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
358 confirmation.getAlpha(), showPrompt ? 0f : 1f);
359 confirmAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
360
361 prompt.setVisibility(showPrompt ? VISIBLE : GONE);
362 confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
Julia Reynoldse0341482018-03-08 14:42:50 -0500363 header.setVisibility(showPrompt ? VISIBLE : GONE);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500364
365 mExpandAnimation = new AnimatorSet();
366 mExpandAnimation.playTogether(promptAnim, confirmAnim);
367 mExpandAnimation.setDuration(150);
368 mExpandAnimation.addListener(new AnimatorListenerAdapter() {
369 boolean cancelled = false;
370
371 @Override
372 public void onAnimationCancel(Animator animation) {
373 cancelled = true;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500374 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500375
376 @Override
377 public void onAnimationEnd(Animator animation) {
378 if (!cancelled) {
379 prompt.setVisibility(showPrompt ? VISIBLE : GONE);
380 confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
381 }
382 }
Mady Mellor87d79452017-01-10 11:52:52 -0800383 });
Julia Reynolds437cdb12018-01-03 12:27:24 -0500384 mExpandAnimation.start();
Mady Mellor87d79452017-01-10 11:52:52 -0800385 }
386
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400387 @Override
388 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
389 super.onInitializeAccessibilityEvent(event);
390 if (mGutsContainer != null &&
391 event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
392 if (mGutsContainer.isExposed()) {
393 event.getText().add(mContext.getString(
394 R.string.notification_channel_controls_opened_accessibility, mAppName));
395 } else {
396 event.getText().add(mContext.getString(
397 R.string.notification_channel_controls_closed_accessibility, mAppName));
398 }
399 }
400 }
401
Julia Reynolds3aedded2017-03-31 14:42:09 -0400402 private Intent getAppSettingsIntent(PackageManager pm, String packageName,
403 NotificationChannel channel, int id, String tag) {
404 Intent intent = new Intent(Intent.ACTION_MAIN)
405 .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
406 .setPackage(packageName);
407 final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
408 intent,
409 PackageManager.MATCH_DEFAULT_ONLY
410 );
411 if (resolveInfos == null || resolveInfos.size() == 0 || resolveInfos.get(0) == null) {
412 return null;
413 }
414 final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
415 intent.setClassName(activityInfo.packageName, activityInfo.name);
416 if (channel != null) {
417 intent.putExtra(Notification.EXTRA_CHANNEL_ID, channel.getId());
418 }
419 intent.putExtra(Notification.EXTRA_NOTIFICATION_ID, id);
420 intent.putExtra(Notification.EXTRA_NOTIFICATION_TAG, tag);
421 return intent;
422 }
423
Julia Reynolds437cdb12018-01-03 12:27:24 -0500424 private void closeControls(View v) {
425 int[] parentLoc = new int[2];
426 int[] targetLoc = new int[2];
427 mGutsContainer.getLocationOnScreen(parentLoc);
428 v.getLocationOnScreen(targetLoc);
429 final int centerX = v.getWidth() / 2;
430 final int centerY = v.getHeight() / 2;
431 final int x = targetLoc[0] - parentLoc[0] + centerX;
432 final int y = targetLoc[1] - parentLoc[1] + centerY;
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500433 mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500434 }
435
Mady Mellor87d79452017-01-10 11:52:52 -0800436 @Override
Mady Mellor95d743c2017-01-10 12:05:27 -0800437 public void setGutsParent(NotificationGuts guts) {
438 mGutsContainer = guts;
Mady Mellor87d79452017-01-10 11:52:52 -0800439 }
440
441 @Override
Mady Mellor434180c2017-02-13 11:29:42 -0800442 public boolean willBeRemoved() {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500443 return hasImportanceChanged();
Mady Mellor434180c2017-02-13 11:29:42 -0800444 }
445
446 @Override
Mady Mellor87d79452017-01-10 11:52:52 -0800447 public View getContentView() {
448 return this;
449 }
450
451 @Override
Mady Mellorc2dbe492017-03-30 13:22:03 -0700452 public boolean handleCloseControls(boolean save, boolean force) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500453 // Save regardless of the importance so we can lock the importance field if the user wants
454 // to keep getting notifications
455 if (save) {
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400456 if (mCheckSaveListener != null) {
Eliot Courtney47098cb2017-10-18 17:30:30 +0900457 mCheckSaveListener.checkSave(this::saveImportance, mSbn);
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400458 } else {
459 saveImportance();
460 }
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500461 }
Mady Mellor87d79452017-01-10 11:52:52 -0800462 return false;
463 }
Mady Mellore09fb702017-03-30 13:23:29 -0700464
465 @Override
466 public int getActualHeight() {
467 return getHeight();
468 }
Mady Mellor87d79452017-01-10 11:52:52 -0800469}