blob: bdbc9b32cbce6c99476937635a317bddafd2de95 [file] [log] [blame]
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 android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
import com.android.systemui.statusbar.NotificationGuts.OnSettingsClickListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.Set;
/**
* The guts of a notification revealed when performing a long press.
*/
public class NotificationInfo extends LinearLayout implements GutsContent {
private static final String TAG = "InfoGuts";
private INotificationManager mINotificationManager;
private int mStartingUserImportance;
private StatusBarNotification mStatusBarNotification;
private NotificationChannel mNotificationChannel;
private ImageView mAutoButton;
private TextView mImportanceSummary;
private TextView mImportanceTitle;
private boolean mAuto;
private View mImportanceGroup;
private View mChannelDisabled;
private Switch mChannelEnabledSwitch;
private RadioButton mMinImportanceButton;
private RadioButton mLowImportanceButton;
private RadioButton mDefaultImportanceButton;
private RadioButton mHighImportanceButton;
private GutsInteractionListener mGutsInteractionListener;
public NotificationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface OnSettingsClickListener {
void onClick(View v, int appUid);
}
public void bindNotification(final PackageManager pm,
final INotificationManager iNotificationManager,
final StatusBarNotification sbn, final NotificationChannel channel,
OnSettingsClickListener onSettingsClick,
OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
mINotificationManager = iNotificationManager;
mNotificationChannel = channel;
mStatusBarNotification = sbn;
mStartingUserImportance = channel.getImportance();
final String pkg = sbn.getPackageName();
int appUid = -1;
String appname = pkg;
Drawable pkgicon = null;
try {
final ApplicationInfo info = pm.getApplicationInfo(pkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
if (info != null) {
appUid = info.uid;
appname = String.valueOf(pm.getApplicationLabel(info));
pkgicon = pm.getApplicationIcon(info);
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
pkgicon = pm.getDefaultActivityIcon();
}
// If this is the placeholder channel, don't use our channel-specific text.
String appNameText;
CharSequence channelNameText;
if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
appNameText = appname;
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
channelNameText = channel.getName();
}
((TextView) findViewById(R.id.pkgname)).setText(appNameText);
((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
// Settings button.
final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
if (appUid >= 0 && onSettingsClick != null) {
final int appUidF = appUid;
settingsButton.setOnClickListener(
(View view) -> {
onSettingsClick.onClick(view, appUidF);
});
settingsButton.setText(R.string.notification_more_settings);
} else {
settingsButton.setVisibility(View.GONE);
}
// Done button.
final TextView doneButton = (TextView) findViewById(R.id.done);
doneButton.setText(R.string.notification_done);
doneButton.setOnClickListener(onDoneClick);
boolean nonBlockable = false;
try {
final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
if (nonBlockablePkgs != null) {
nonBlockable |= nonBlockablePkgs.contains(pkg);
}
final View importanceButtons = findViewById(R.id.importance_buttons);
bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
// Importance Text (hardcoded to 4 importance levels)
final ViewGroup importanceTextGroup = (ViewGroup) findViewById(
R.id.importance_buttons_text);
final int size = importanceTextGroup.getChildCount();
for (int i = 0; i < size; i++) {
int importanceNameResId = 0;
int importanceDescResId = 0;
switch (i) {
case 0:
importanceNameResId = R.string.high_importance;
importanceDescResId = R.string.notification_importance_high;
break;
case 1:
importanceNameResId = R.string.default_importance;
importanceDescResId = R.string.notification_importance_default;
break;
case 2:
importanceNameResId = R.string.low_importance;
importanceDescResId = R.string.notification_importance_low;
break;
case 3:
importanceNameResId = R.string.min_importance;
importanceDescResId = R.string.notification_importance_min;
break;
default:
Log.e(TAG, "Too many importance groups in this layout.");
break;
}
final ViewGroup importanceChildGroup = (ViewGroup) importanceTextGroup.getChildAt(i);
((TextView) importanceChildGroup.getChildAt(0)).setText(importanceNameResId);
((TextView) importanceChildGroup.getChildAt(1)).setText(importanceDescResId);
}
// Top-level importance group
mImportanceGroup = findViewById(R.id.importance);
mChannelDisabled = findViewById(R.id.channel_disabled);
updateImportanceGroup();
}
public boolean hasImportanceChanged() {
return mStartingUserImportance != getSelectedImportance();
}
public void saveImportance() {
int selectedImportance = getSelectedImportance();
if (selectedImportance == mStartingUserImportance) {
return;
}
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
selectedImportance - mStartingUserImportance);
mNotificationChannel.setImportance(selectedImportance);
try {
mINotificationManager.updateNotificationChannelForPackage(
mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
mNotificationChannel);
} catch (RemoteException e) {
// :(
}
}
private int getSelectedImportance() {
if (!mChannelEnabledSwitch.isChecked()) {
return NotificationManager.IMPORTANCE_NONE;
} else if (mMinImportanceButton.isChecked()) {
return NotificationManager.IMPORTANCE_MIN;
} else if (mLowImportanceButton.isChecked()) {
return NotificationManager.IMPORTANCE_LOW;
} else if (mDefaultImportanceButton.isChecked()) {
return NotificationManager.IMPORTANCE_DEFAULT;
} else if (mHighImportanceButton.isChecked()) {
return NotificationManager.IMPORTANCE_HIGH;
} else {
return NotificationManager.IMPORTANCE_UNSPECIFIED;
}
}
private void bindToggles(final View importanceButtons, final int importance,
final boolean nonBlockable) {
// Enabled Switch
mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
mChannelEnabledSwitch.setChecked(importance != NotificationManager.IMPORTANCE_NONE);
mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
// Importance Buttons
mMinImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.min_importance);
mLowImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.low_importance);
mDefaultImportanceButton = (RadioButton) importanceButtons
.findViewById(R.id.default_importance);
mHighImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.high_importance);
// Set to current importance setting
switch (importance) {
case NotificationManager.IMPORTANCE_UNSPECIFIED:
case NotificationManager.IMPORTANCE_NONE:
break;
case NotificationManager.IMPORTANCE_MIN:
mMinImportanceButton.setChecked(true);
break;
case NotificationManager.IMPORTANCE_LOW:
mLowImportanceButton.setChecked(true);
break;
case NotificationManager.IMPORTANCE_DEFAULT:
mDefaultImportanceButton.setChecked(true);
break;
case NotificationManager.IMPORTANCE_HIGH:
case NotificationManager.IMPORTANCE_MAX:
mHighImportanceButton.setChecked(true);
break;
}
// Callback when checked.
mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
mGutsInteractionListener.onInteraction(NotificationInfo.this);
updateImportanceGroup();
});
((RadioGroup) importanceButtons).setOnCheckedChangeListener(
(buttonView, isChecked) -> {
mGutsInteractionListener.onInteraction(NotificationInfo.this);
});
}
private void updateImportanceGroup() {
final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
mImportanceGroup.setVisibility(disabled ? View.GONE : View.VISIBLE);
mChannelDisabled.setVisibility(disabled ? View.VISIBLE : View.GONE);
}
public void closeControls() {
if (mGutsInteractionListener != null) {
mGutsInteractionListener.closeGuts(this);
}
}
@Override
public void setInteractionListener(GutsInteractionListener listener) {
mGutsInteractionListener = listener;
}
@Override
public View getContentView() {
return this;
}
@Override
public boolean handleCloseControls() {
return false;
}
}