blob: cfaa9e6238e79197b7b5a9b608cc42e6f9e8b93a [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
Mady Mellor87d79452017-01-10 11:52:52 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.app.INotificationManager;
22import android.app.NotificationChannel;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050023import android.app.NotificationChannelGroup;
Mady Mellor87d79452017-01-10 11:52:52 -080024import android.app.NotificationManager;
25import android.content.Context;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageInfo;
28import android.content.pm.PackageManager;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050029import android.content.pm.ParceledListSlice;
Mady Mellor87d79452017-01-10 11:52:52 -080030import android.content.res.ColorStateList;
31import android.content.res.TypedArray;
32import android.graphics.Canvas;
33import android.graphics.drawable.Drawable;
34import android.os.Handler;
35import android.os.RemoteException;
36import android.os.ServiceManager;
37import android.service.notification.NotificationListenerService;
38import android.service.notification.StatusBarNotification;
39import android.util.AttributeSet;
40import android.util.Log;
41import android.view.View;
42import android.view.ViewAnimationUtils;
43import android.view.ViewGroup;
44import android.view.View.OnClickListener;
45import android.widget.CompoundButton;
46import android.widget.ImageView;
47import android.widget.LinearLayout;
Mady Mellor87d79452017-01-10 11:52:52 -080048import android.widget.SeekBar;
49import android.widget.Switch;
50import android.widget.TextView;
51
52import com.android.internal.logging.MetricsLogger;
53import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
54import com.android.settingslib.Utils;
55import com.android.systemui.Interpolators;
56import com.android.systemui.R;
57import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
58import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
59import com.android.systemui.statusbar.NotificationGuts.OnSettingsClickListener;
60import com.android.systemui.statusbar.stack.StackStateAnimator;
61
62import java.util.Set;
63
64/**
65 * The guts of a notification revealed when performing a long press.
66 */
67public class NotificationInfo extends LinearLayout implements GutsContent {
68 private static final String TAG = "InfoGuts";
69
70 private INotificationManager mINotificationManager;
71 private int mStartingUserImportance;
72 private StatusBarNotification mStatusBarNotification;
73 private NotificationChannel mNotificationChannel;
74
75 private ImageView mAutoButton;
76 private TextView mImportanceSummary;
77 private TextView mImportanceTitle;
78 private boolean mAuto;
79
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050080 private TextView mNumChannelsView;
81 private View mChannelDisabledView;
Mady Mellor87d79452017-01-10 11:52:52 -080082 private Switch mChannelEnabledSwitch;
Mady Mellor87d79452017-01-10 11:52:52 -080083
84 private GutsInteractionListener mGutsInteractionListener;
85
86 public NotificationInfo(Context context, AttributeSet attrs) {
87 super(context, attrs);
88 }
89
Jason Monk2a6ea9c2017-01-26 11:14:51 -050090 public interface OnSettingsClickListener {
Mady Mellor87d79452017-01-10 11:52:52 -080091 void onClick(View v, int appUid);
92 }
93
Jason Monk2a6ea9c2017-01-26 11:14:51 -050094 public void bindNotification(final PackageManager pm,
95 final INotificationManager iNotificationManager,
Mady Mellor87d79452017-01-10 11:52:52 -080096 final StatusBarNotification sbn, final NotificationChannel channel,
97 OnSettingsClickListener onSettingsClick,
98 OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
99 mINotificationManager = iNotificationManager;
100 mNotificationChannel = channel;
101 mStatusBarNotification = sbn;
102 mStartingUserImportance = channel.getImportance();
103
104 final String pkg = sbn.getPackageName();
105 int appUid = -1;
106 String appname = pkg;
107 Drawable pkgicon = null;
108 try {
109 final ApplicationInfo info = pm.getApplicationInfo(pkg,
110 PackageManager.MATCH_UNINSTALLED_PACKAGES
111 | PackageManager.MATCH_DISABLED_COMPONENTS
112 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
113 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
114 if (info != null) {
115 appUid = info.uid;
116 appname = String.valueOf(pm.getApplicationLabel(info));
117 pkgicon = pm.getApplicationIcon(info);
118 }
119 } catch (PackageManager.NameNotFoundException e) {
120 // app is gone, just show package name and generic icon
121 pkgicon = pm.getDefaultActivityIcon();
122 }
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500123 ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
124
125 int numChannels = 1;
126 try {
127 numChannels = iNotificationManager.getNumNotificationChannelsForPackage(
128 pkg, appUid, false /* includeDeleted */);
129 } catch (RemoteException e) {
130 Log.e(TAG, e.toString());
131 }
132
133 mNumChannelsView = (TextView) (findViewById(R.id.num_channels_desc));
134 mNumChannelsView.setText(String.format(mContext.getResources().getQuantityString(
135 R.plurals.notification_num_channels_desc, numChannels), numChannels));
Mady Mellor87d79452017-01-10 11:52:52 -0800136
137 // If this is the placeholder channel, don't use our channel-specific text.
138 String appNameText;
139 CharSequence channelNameText;
140 if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
141 appNameText = appname;
142 channelNameText = mContext.getString(R.string.notification_header_default_channel);
143 } else {
144 appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
145 channelNameText = channel.getName();
146 }
147 ((TextView) findViewById(R.id.pkgname)).setText(appNameText);
148 ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
149
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500150 // Set group information if this channel has an associated group.
151 CharSequence groupName = null;
152 if (channel.getGroup() != null) {
153 try {
154 final NotificationChannelGroup notificationChannelGroup =
155 iNotificationManager.getNotificationChannelGroupForPackage(
156 channel.getGroup(), pkg, appUid);
157 if (notificationChannelGroup != null) {
158 groupName = notificationChannelGroup.getName();
159 }
160 } catch (RemoteException e) {
161 Log.e(TAG, e.toString());
162 }
Mady Mellor87d79452017-01-10 11:52:52 -0800163 }
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500164 TextView groupNameView = ((TextView) findViewById(R.id.group_name));
165 TextView groupDividerView = ((TextView) findViewById(R.id.pkg_group_divider));
166 if (groupName != null) {
167 groupNameView.setText(groupName);
168 groupNameView.setVisibility(View.VISIBLE);
169 groupDividerView.setVisibility(View.VISIBLE);
170 } else {
171 groupNameView.setVisibility(View.GONE);
172 groupDividerView.setVisibility(View.GONE);
173 }
Mady Mellor87d79452017-01-10 11:52:52 -0800174
175 boolean nonBlockable = false;
176 try {
177 final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
178 nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
179 } catch (PackageManager.NameNotFoundException e) {
180 // unlikely.
181 }
182 if (nonBlockablePkgs != null) {
183 nonBlockable |= nonBlockablePkgs.contains(pkg);
184 }
185
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500186 bindButtons(nonBlockable);
Mady Mellor87d79452017-01-10 11:52:52 -0800187
188 // Top-level importance group
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500189 mChannelDisabledView = findViewById(R.id.channel_disabled);
190 updateImportanceDisplay();
191
192 // Settings button.
193 final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
194 if (appUid >= 0 && onSettingsClick != null) {
195 final int appUidF = appUid;
196 settingsButton.setOnClickListener(
197 (View view) -> {
198 onSettingsClick.onClick(view, appUidF);
199 });
200 if (numChannels > 1) {
201 settingsButton.setText(R.string.notification_all_categories);
202 } else {
203 settingsButton.setText(R.string.notification_more_settings);
204 }
205
206 } else {
207 settingsButton.setVisibility(View.GONE);
208 }
209
210 // Done button.
211 final TextView doneButton = (TextView) findViewById(R.id.done);
212 doneButton.setText(R.string.notification_done);
213 doneButton.setOnClickListener(onDoneClick);
Mady Mellor87d79452017-01-10 11:52:52 -0800214 }
215
216 public boolean hasImportanceChanged() {
217 return mStartingUserImportance != getSelectedImportance();
218 }
219
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500220 private void saveImportance() {
Mady Mellor87d79452017-01-10 11:52:52 -0800221 int selectedImportance = getSelectedImportance();
222 if (selectedImportance == mStartingUserImportance) {
223 return;
224 }
225 MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
226 selectedImportance - mStartingUserImportance);
227 mNotificationChannel.setImportance(selectedImportance);
228 try {
229 mINotificationManager.updateNotificationChannelForPackage(
230 mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
231 mNotificationChannel);
232 } catch (RemoteException e) {
233 // :(
234 }
235 }
236
237 private int getSelectedImportance() {
238 if (!mChannelEnabledSwitch.isChecked()) {
239 return NotificationManager.IMPORTANCE_NONE;
Mady Mellor87d79452017-01-10 11:52:52 -0800240 } else {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500241 return mStartingUserImportance;
Mady Mellor87d79452017-01-10 11:52:52 -0800242 }
243 }
244
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500245 private void bindButtons(final boolean nonBlockable) {
Mady Mellor87d79452017-01-10 11:52:52 -0800246 // Enabled Switch
247 mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500248 mChannelEnabledSwitch.setChecked(
249 mStartingUserImportance != NotificationManager.IMPORTANCE_NONE);
Mady Mellor87d79452017-01-10 11:52:52 -0800250 mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
251
Mady Mellor87d79452017-01-10 11:52:52 -0800252 // Callback when checked.
253 mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500254 if (mGutsInteractionListener != null) {
255 mGutsInteractionListener.onInteraction(NotificationInfo.this);
256 }
257 updateImportanceDisplay();
Mady Mellor87d79452017-01-10 11:52:52 -0800258 });
Mady Mellor87d79452017-01-10 11:52:52 -0800259 }
260
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500261 private void updateImportanceDisplay() {
Mady Mellor87d79452017-01-10 11:52:52 -0800262 final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500263 mChannelDisabledView.setVisibility(disabled ? View.VISIBLE : View.GONE);
264 if (disabled) {
265 // To be replaced by disabled text.
266 mNumChannelsView.setVisibility(View.GONE);
267 } else if (mNotificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
268 mNumChannelsView.setVisibility(View.INVISIBLE);
269 } else {
270 mNumChannelsView.setVisibility(View.VISIBLE);
Mady Mellor87d79452017-01-10 11:52:52 -0800271 }
272 }
273
274 @Override
275 public void setInteractionListener(GutsInteractionListener listener) {
276 mGutsInteractionListener = listener;
277 }
278
279 @Override
280 public View getContentView() {
281 return this;
282 }
283
284 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500285 public boolean handleCloseControls(boolean save) {
286 if (save) {
287 saveImportance();
288 }
Mady Mellor87d79452017-01-10 11:52:52 -0800289 return false;
290 }
291}