Change NotificationGuts to contain a view

NotificationGuts is now given a view to display, the notification
management controls have been moved into their own view.

NotificationGuts is provided a view to show via a MenuItem.

This allows configuration via the NotificationMenuRowProvider Plugin.

Test: manual
Change-Id: I68cb23ea2cada30cc6e930fa8c03e0aa4014dfe2
This commit is contained in:
Mady Mellor
2017-01-10 11:52:52 -08:00
parent 761cde1173
commit 87d7945f06
9 changed files with 639 additions and 427 deletions

View File

@@ -3,6 +3,7 @@ package com.android.systemui.plugins.statusbar;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.view.View;
import java.util.ArrayList;
@@ -26,14 +27,34 @@ public interface NotificationMenuRowProvider extends Plugin {
public void onMenuReset(View row);
}
public interface GutsInteractionListener {
public void onInteraction(View view);
public void closeGuts(View view);
}
public interface GutsContent {
public void setInteractionListener(GutsInteractionListener listener);
public View getContentView();
public boolean handleCloseControls();
}
public static class MenuItem {
public Drawable icon;
public String menuDescription;
public View menuView;
public GutsContent gutsContent;
public MenuItem(Drawable i, String s) {
public MenuItem(Drawable i, String s, GutsContent content) {
icon = i;
menuDescription = s;
gutsContent = content;
}
public View getGutsView() {
return gutsContent.getContentView();
}
public boolean onTouch(View v, int x, int y) {

View File

@@ -23,125 +23,4 @@
android:visibility="gone"
android:clickable="true"
android:gravity="top|start"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="8dp"
android:background="@color/notification_guts_bg_color"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- header -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingEnd="8dp"
android:paddingBottom="15dp"
android:id="@+id/notification_guts_header">
<TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
style="@style/TextAppearance.NotificationGuts.Secondary" />
<TextView
android:id="@+id/channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/pkgname"
style="@style/TextAppearance.NotificationGuts.Header" />
<Switch
android:id="@+id/channel_enabled_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@null" />
</RelativeLayout>
<!-- Importance radio buttons -->
<LinearLayout
android:id="@+id/importance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/importance_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="@*android:dimen/notification_content_margin_end">
<RadioButton
android:id="@+id/high_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/default_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/low_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/min_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
</RadioGroup>
<LinearLayout
android:id="@+id/importance_buttons_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
</LinearLayout>
</LinearLayout>
<!-- Channel Disabled Text -->
<TextView
android:id="@+id/channel_disabled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationGuts.Secondary" />
<!-- Settings and Done buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingTop="16dp"
android:paddingBottom="8dp" >
<TextView
android:id="@+id/more_settings"
android:text="@string/notification_more_settings"
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:focusable="true" />
<TextView
android:id="@+id/done"
android:text="@string/notification_done"
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:focusable="true"/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
android:theme="@*android:style/Theme.DeviceDefault.Light"/>

View File

@@ -0,0 +1,146 @@
<?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.NotificationInfo
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/notification_guts"
android:clickable="true"
android:gravity="top|start"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="8dp"
android:background="@color/notification_guts_bg_color"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- header -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingEnd="8dp"
android:paddingBottom="15dp"
android:id="@+id/notification_guts_header">
<TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
style="@style/TextAppearance.NotificationGuts.Secondary" />
<TextView
android:id="@+id/channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/pkgname"
style="@style/TextAppearance.NotificationGuts.Header" />
<Switch
android:id="@+id/channel_enabled_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@null" />
</RelativeLayout>
<!-- Importance radio buttons -->
<LinearLayout
android:id="@+id/importance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/importance_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="@*android:dimen/notification_content_margin_end">
<RadioButton
android:id="@+id/high_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/default_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/low_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/min_importance"
android:layout_width="wrap_content"
android:layout_height="@dimen/notification_inline_importance_height"
style="@style/TextAppearance.NotificationGuts.Radio"
android:buttonTint="@color/notification_guts_buttons" />
</RadioGroup>
<LinearLayout
android:id="@+id/importance_buttons_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
<include layout="@layout/notification_guts_importance_text"/>
</LinearLayout>
</LinearLayout>
<!-- Channel Disabled Text -->
<TextView
android:id="@+id/channel_disabled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationGuts.Secondary" />
<!-- Settings and Done buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingTop="16dp"
android:paddingBottom="8dp" >
<TextView
android:id="@+id/more_settings"
android:text="@string/notification_more_settings"
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:focusable="true" />
<TextView
android:id="@+id/done"
android:text="@string/notification_done"
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:focusable="true"/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationInfo>

View File

@@ -101,6 +101,8 @@ import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -247,6 +249,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
private MenuItem mGutsMenuItem;
private KeyboardShortcuts mKeyboardShortcuts;
@@ -702,6 +705,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
@Override
public void start() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -967,7 +971,7 @@ public abstract class BaseStatusBar extends SystemUI implements
entry.row.reInflateViews();
if (exposedGuts) {
mNotificationGutsExposed = entry.row.getGuts();
bindGuts(entry.row);
bindGuts(entry.row, mGutsMenuItem);
}
inflateViews(entry, mStackScroller);
}
@@ -1032,6 +1036,7 @@ public abstract class BaseStatusBar extends SystemUI implements
@Override
public boolean onDismiss() {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
@@ -1045,11 +1050,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}, false /* afterKeyguardGone */);
}
private void bindGuts(final ExpandableNotificationRow row) {
private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
row.inflateGuts();
row.setGutsView(item);
final StatusBarNotification sbn = row.getStatusBarNotification();
final NotificationChannel channel = row.getEntry().channel;
PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
row.setTag(sbn.getPackageName());
final NotificationGuts guts = row.getGuts();
guts.setClosedListener((NotificationGuts g) -> {
@@ -1059,43 +1063,48 @@ public abstract class BaseStatusBar extends SystemUI implements
mNotificationGutsExposed = null;
});
final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
final String pkg = sbn.getPackageName();
final NotificationGuts.OnSettingsClickListener onSettingsClick =
(View v, int appUid) -> {
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
guts.resetFalsingCheck();
startAppNotificationSettingsActivity(pkg, appUid);
};
final View.OnClickListener onDoneClick =
(View v) -> {
// If the user has security enabled, show challenge if the setting is changed.
if (guts.hasImportanceChanged()
&& isLockscreenPublicMode(sbn.getUser().getIdentifier())
&& (mState == StatusBarState.KEYGUARD
|| mState == StatusBarState.SHADE_LOCKED)) {
OnDismissAction dismissAction = new OnDismissAction() {
@Override
public boolean onDismiss() {
closeControls(row, guts, v);
return true;
}
};
onLockedNotificationImportanceChange(dismissAction);
} else {
closeControls(row, guts, v);
}
};
guts.bindNotification(pmUser, iNotificationManager, sbn, channel,
onSettingsClick, onDoneClick, mNonBlockablePkgs);
if (item.gutsContent instanceof NotificationInfo) {
final NotificationChannel channel = row.getEntry().channel;
PackageManager pmUser = getPackageManagerForUser(mContext,
sbn.getUser().getIdentifier());
final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
final String pkg = sbn.getPackageName();
NotificationInfo info = (NotificationInfo) item.gutsContent;
final NotificationInfo.OnSettingsClickListener onSettingsClick = (View v,
int appUid) -> {
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
guts.resetFalsingCheck();
startAppNotificationSettingsActivity(pkg, appUid);
};
final View.OnClickListener onDoneClick = (View v) -> {
// If the user has security enabled, show challenge if the setting is changed.
if (info.hasImportanceChanged()
&& isLockscreenPublicMode(sbn.getUser().getIdentifier())
&& (mState == StatusBarState.KEYGUARD
|| mState == StatusBarState.SHADE_LOCKED)) {
OnDismissAction dismissAction = new OnDismissAction() {
@Override
public boolean onDismiss() {
saveAndCloseNotificationMenu(info, row, guts, v);
return true;
}
};
onLockedNotificationImportanceChange(dismissAction);
} else {
saveAndCloseNotificationMenu(info, row, guts, v);
}
};
info.bindNotification(pmUser, iNotificationManager, sbn, channel, onSettingsClick,
onDoneClick,
mNonBlockablePkgs);
}
}
private void closeControls(
private void saveAndCloseNotificationMenu(NotificationInfo info,
ExpandableNotificationRow row, NotificationGuts guts, View done) {
guts.resetFalsingCheck();
info.saveImportance();
int[] rowLocation = new int[2];
int[] doneLocation = new int[2];
row.getLocationOnScreen(rowLocation);
@@ -1111,7 +1120,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
public boolean onLongPress(View v, final int x, final int y) {
public boolean onLongPress(View v, final int x, final int y,
MenuItem item) {
if (!(v instanceof ExpandableNotificationRow)) {
return false;
}
@@ -1121,10 +1131,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
bindGuts(row);
bindGuts(row, item);
NotificationGuts guts = row.getGuts();
// Assume we are a status_bar_notification_row
final NotificationGuts guts = row.getGuts();
if (guts == null) {
// This view has no guts. Examples are the more card or the dismiss all view
return false;
@@ -1142,6 +1152,7 @@ public abstract class BaseStatusBar extends SystemUI implements
guts.setVisibility(View.INVISIBLE);
// Post to ensure the the guts are properly laid out.
guts.post(new Runnable() {
@Override
public void run() {
if (row.getWindowToken() == null) {
Log.e(TAG, "Trying to show notification guts, but not attached to "
@@ -1172,6 +1183,7 @@ public abstract class BaseStatusBar extends SystemUI implements
row.closeRemoteInput();
mStackScroller.onHeightChanged(row, true /* needsAnimation */);
mNotificationGutsExposed = guts;
mGutsMenuItem = item;
}
});
return true;
@@ -1483,6 +1495,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected class H extends Handler {
@Override
public void handleMessage(Message m) {
switch (m.what) {
case MSG_SHOW_RECENT_APPS:
@@ -1752,6 +1765,7 @@ public abstract class BaseStatusBar extends SystemUI implements
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
public boolean onDismiss() {
new Thread() {
@Override
@@ -1802,6 +1816,7 @@ public abstract class BaseStatusBar extends SystemUI implements
private final class NotificationClicker implements View.OnClickListener {
private final int[] mTmpInt2 = new int[2];
@Override
public void onClick(final View v) {
if (!(v instanceof ExpandableNotificationRow)) {
Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
@@ -1845,6 +1860,7 @@ public abstract class BaseStatusBar extends SystemUI implements
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
public boolean onDismiss() {
if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
// Release the HUN notification to the shade.

View File

@@ -50,6 +50,7 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -666,6 +667,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mHeadsUpManager = headsUpManager;
}
public void setGutsView(MenuItem item) {
if (mGuts != null) {
item.gutsContent.setInteractionListener(mGuts);
mGuts.setGutsContent(item.gutsContent);
}
}
public void reInflateViews() {
initDimens();
if (mIsSummaryWithChildren) {

View File

@@ -40,6 +40,7 @@ import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
@@ -53,6 +54,8 @@ 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;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.Set;
@@ -60,7 +63,8 @@ import java.util.Set;
/**
* The guts of a notification revealed when performing a long press.
*/
public class NotificationGuts extends LinearLayout {
public class NotificationGuts extends FrameLayout
implements NotificationMenuRowProvider.GutsInteractionListener {
private static final String TAG = "NotificationGuts";
private static final long CLOSE_GUTS_DELAY = 8000;
@@ -69,24 +73,14 @@ public class NotificationGuts extends LinearLayout {
private int mClipBottomAmount;
private int mActualHeight;
private boolean mExposed;
private INotificationManager mINotificationManager;
private int mStartingUserImportance;
private StatusBarNotification mStatusBarNotification;
private NotificationChannel mNotificationChannel;
private View mImportanceGroup;
private View mChannelDisabled;
private Switch mChannelEnabledSwitch;
private RadioButton mMinImportanceButton;
private RadioButton mLowImportanceButton;
private RadioButton mDefaultImportanceButton;
private RadioButton mHighImportanceButton;
private Handler mHandler;
private Runnable mFalsingCheck;
private boolean mNeedsFalsingProtection;
private OnGutsClosedListener mListener;
private GutsContent mGutsContent;
public interface OnGutsClosedListener {
public void onGutsClosed(NotificationGuts guts);
}
@@ -103,11 +97,22 @@ public class NotificationGuts extends LinearLayout {
}
}
};
final TypedArray ta =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Theme, 0, 0);
final TypedArray ta = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.Theme, 0, 0);
ta.recycle();
}
public NotificationGuts(Context context) {
this(context, null);
}
public void setGutsContent(GutsContent content) {
mGutsContent = content;
removeAllViews();
addView(mGutsContent.getContentView());
}
public void resetFalsingCheck() {
mHandler.removeCallbacks(mFalsingCheck);
if (mNeedsFalsingProtection && mExposed) {
@@ -165,213 +170,23 @@ public class NotificationGuts extends LinearLayout {
void onClick(View v, int appUid);
}
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();
}
private 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) -> {
resetFalsingCheck();
updateImportanceGroup();
});
((RadioGroup) importanceButtons).setOnCheckedChangeListener(
(buttonView, isChecked) -> { resetFalsingCheck(); });
}
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(int x, int y, boolean saveImportance) {
if (saveImportance) {
saveImportance();
}
if (getWindowToken() == null) {
if (mListener != null) {
mListener.onGutsClosed(this);
}
return;
}
if (mGutsContent == null || !mGutsContent.handleCloseControls()) {
animateClose(x, y);
}
setExposed(false, mNeedsFalsingProtection);
if (mListener != null) {
mListener.onGutsClosed(this);
}
}
private void animateClose(int x, int y) {
if (x == -1 || y == -1) {
x = (getLeft() + getRight()) / 2;
y = (getTop() + getHeight() / 2);
@@ -391,10 +206,6 @@ public class NotificationGuts extends LinearLayout {
}
});
a.start();
setExposed(false, mNeedsFalsingProtection);
if (mListener != null) {
mListener.onGutsClosed(this);
}
}
public void setActualHeight(int actualHeight) {
@@ -439,4 +250,14 @@ public class NotificationGuts extends LinearLayout {
public boolean isExposed() {
return mExposed;
}
@Override
public void onInteraction(View view) {
resetFalsingCheck();
}
@Override
public void closeGuts(View view) {
closeControls(-1 /* x */, -1 /* y */, true /* notify */);
}
}

View File

@@ -0,0 +1,319 @@
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);
}
interface OnSettingsClickListener {
void onClick(View v, int appUid);
}
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;
}
}

View File

@@ -102,7 +102,9 @@ public class NotificationMenuRow extends FrameLayout
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);
MenuItem settings = new MenuItem(d, s);
NotificationInfo content = (NotificationInfo) LayoutInflater.from(context).inflate(
R.layout.notification_info, null, false);
MenuItem settings = new MenuItem(d, s, content);
return settings;
}

View File

@@ -63,7 +63,7 @@ public class NotificationGutsTest {
private static final String TEST_CHANNEL = "test_channel";
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
private NotificationGuts mNotificationGuts;
private NotificationInfo mNotificationInfo;
private final INotificationManager mMockINotificationManager = mock(INotificationManager.class);
private final PackageManager mMockPackageManager = mock(PackageManager.class);
private NotificationChannel mNotificationChannel;
@@ -76,7 +76,7 @@ public class NotificationGutsTest {
// Inflate the layout
final LayoutInflater layoutInflater =
LayoutInflater.from(InstrumentationRegistry.getTargetContext());
mNotificationGuts = (NotificationGuts) layoutInflater.inflate(R.layout.notification_guts,
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
null);
// PackageManager must return a packageInfo and applicationInfo.
@@ -98,18 +98,18 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.pkgname);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
}
@Test
@UiThreadTest
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.channel_name);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -117,12 +117,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel,
(View v, int appUid) -> { latch.countDown(); }, null, null);
final TextView settingsButton =
(TextView) mNotificationGuts.findViewById(R.id.more_settings);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
settingsButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -132,12 +132,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForDone() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null,
(View v) -> { latch.countDown(); },
null);
final TextView doneButton = (TextView) mNotificationGuts.findViewById(R.id.done);
final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done);
doneButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -146,38 +146,38 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
public void testHasImportanceChanged_DefaultsToFalse() throws Exception {
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
assertFalse(mNotificationGuts.hasImportanceChanged());
assertFalse(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testHasImportanceChanged_ReturnsTrueAfterButtonChecked() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
// Find the high button and check it.
RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
assertTrue(mNotificationGuts.hasImportanceChanged());
assertTrue(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testImportanceButtonCheckedBasedOnInitialImportance() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
assertTrue(highButton.isChecked());
}
@Test
@UiThreadTest
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -187,10 +187,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -199,10 +199,10 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception {
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
mNotificationGuts.closeControls(-1, -1, true);
mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -211,10 +211,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
mNotificationGuts.closeControls(-1, -1, true);
mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -223,12 +223,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_CallsUpdateNotificationChannelIfChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
mNotificationGuts.closeControls(-1, -1, true);
mNotificationInfo.closeControls();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
assertEquals(NotificationManager.IMPORTANCE_HIGH, mNotificationChannel.getImportance());
@@ -238,12 +238,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfSaveFalse() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
mNotificationGuts.closeControls(-1, -1, false);
mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -252,10 +252,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchOnByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertTrue(enabledSwitch.isChecked());
}
@@ -263,10 +263,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchVisibleByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
}
@@ -274,11 +274,11 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@@ -286,13 +286,13 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationGuts.closeControls(-1, -1, true);
mNotificationInfo.closeControls();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
}
@@ -301,14 +301,14 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchOverridesOtherButtons() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
RadioButton lowButton = (RadioButton) mNotificationGuts.findViewById(R.id.low_importance);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
RadioButton lowButton = (RadioButton) mNotificationInfo.findViewById(R.id.low_importance);
lowButton.setChecked(true);
enabledSwitch.setChecked(false);
mNotificationGuts.closeControls(-1, -1, true);
mNotificationInfo.closeControls();
assertEquals(NotificationManager.IMPORTANCE_NONE, mNotificationChannel.getImportance());
}
}