Merge "Add experience for shortcut-less convos" into rvc-dev am: bc78548368
Change-Id: I5082e8c7b34c956c8fb06d621dadc647f3841f0d
This commit is contained in:
@@ -486,15 +486,8 @@ public class StatusBarNotification implements Parcelable {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public String getShortcutId(Context context) {
|
||||
String conversationId = getNotification().getShortcutId();
|
||||
if (TextUtils.isEmpty(conversationId)
|
||||
&& (Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0)
|
||||
&& getNotification().getNotificationStyle() == Notification.MessagingStyle.class) {
|
||||
conversationId = getId() + getTag() + PLACEHOLDER_CONVERSATION_ID;
|
||||
}
|
||||
return conversationId;
|
||||
public String getShortcutId() {
|
||||
return getNotification().getShortcutId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
200
packages/SystemUI/res/layout/partial_conversation_info.xml
Normal file
200
packages/SystemUI/res/layout/partial_conversation_info.xml
Normal file
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2020, 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.notification.row.PartialConversationInfo
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/notification_guts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@*android:dimen/notification_content_margin_start">
|
||||
|
||||
<!-- Package Info -->
|
||||
<LinearLayout
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_guts_conversation_header_height"
|
||||
android:gravity="center_vertical"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
<ImageView
|
||||
android:id="@+id/conversation_icon"
|
||||
android:layout_width="@dimen/notification_guts_conversation_icon_size"
|
||||
android:layout_height="@dimen/notification_guts_conversation_icon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginEnd="15dp" />
|
||||
<LinearLayout
|
||||
android:id="@+id/names"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:orientation="vertical"
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/notification_guts_conversation_icon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_alignEnd="@id/conversation_icon"
|
||||
android:layout_toEndOf="@id/conversation_icon">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.NotificationImportanceChannel"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/TextAppearance.NotificationImportanceHeader"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:text="@*android:string/notification_header_divider_symbol" />
|
||||
<TextView
|
||||
android:id="@+id/parent_channel_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.NotificationImportanceChannel"/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/pkg_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.NotificationImportanceChannelGroup"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"/>
|
||||
<TextView
|
||||
android:id="@+id/group_divider"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/TextAppearance.NotificationImportanceHeader"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:text="@*android:string/notification_header_divider_symbol" />
|
||||
<TextView
|
||||
android:id="@+id/group_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/delegate_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/TextAppearance.NotificationImportanceHeader"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/notification_delegate_header"
|
||||
android:maxLines="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- end aligned fields -->
|
||||
<ImageButton
|
||||
android:id="@+id/info"
|
||||
android:layout_width="@dimen/notification_importance_toggle_size"
|
||||
android:layout_height="@dimen/notification_importance_toggle_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="@drawable/ripple_drawable"
|
||||
android:contentDescription="@string/notification_more_settings"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:tint="@color/notification_guts_link_icon_tint"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/inline_controls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="@*android:dimen/notification_content_margin_end"
|
||||
android:layout_marginTop="@dimen/notification_guts_option_vertical_padding"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_info"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
<TextView
|
||||
android:id="@+id/non_configurable_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.NotificationImportanceChannelGroup" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/bottom_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/turn_off_notifications"
|
||||
android:text="@string/inline_turn_off_notifications"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:gravity="start|center_vertical"
|
||||
android:minWidth="@dimen/notification_importance_toggle_size"
|
||||
android:minHeight="@dimen/notification_importance_toggle_size"
|
||||
android:maxWidth="200dp"
|
||||
style="@style/TextAppearance.NotificationInfo.Button"/>
|
||||
<TextView
|
||||
android:id="@+id/done"
|
||||
android:text="@string/inline_done_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:gravity="end|center_vertical"
|
||||
android:minWidth="@dimen/notification_importance_toggle_size"
|
||||
android:minHeight="@dimen/notification_importance_toggle_size"
|
||||
android:maxWidth="125dp"
|
||||
style="@style/TextAppearance.NotificationInfo.Button"/>
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</com.android.systemui.statusbar.notification.row.PartialConversationInfo>
|
||||
@@ -1847,6 +1847,9 @@
|
||||
<!-- [CHAR LIMIT=150] Notification Importance title: important conversation level -->
|
||||
<string name="notification_priority_title">Priority</string>
|
||||
|
||||
<!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->
|
||||
<string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> does not support conversation specific settings</string>
|
||||
|
||||
<!-- [CHAR LIMIT=NONE] Empty overflow title -->
|
||||
<string name="bubble_overflow_empty_title">No recent bubbles</string>
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
/**
|
||||
@@ -44,32 +43,18 @@ public class NotificationChannelHelper {
|
||||
if (!TextUtils.isEmpty(channel.getConversationId())) {
|
||||
return channel;
|
||||
}
|
||||
final String conversationId = entry.getSbn().getShortcutId(context);
|
||||
final String conversationId = entry.getSbn().getShortcutId();
|
||||
final String pkg = entry.getSbn().getPackageName();
|
||||
final int appUid = entry.getSbn().getUid();
|
||||
if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)) {
|
||||
if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)
|
||||
|| entry.getRanking().getShortcutInfo() == null) {
|
||||
return channel;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (entry.getRanking().getShortcutInfo() != null) {
|
||||
name = entry.getRanking().getShortcutInfo().getShortLabel().toString();
|
||||
} else {
|
||||
Bundle extras = entry.getSbn().getNotification().extras;
|
||||
String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = extras.getString(Notification.EXTRA_TITLE);
|
||||
}
|
||||
name = nameString;
|
||||
}
|
||||
|
||||
// If this channel is not already a customized conversation channel, create
|
||||
// a custom channel
|
||||
try {
|
||||
// TODO: When shortcuts are enforced remove this and use the shortcut label for naming
|
||||
channel.setName(context.getString(
|
||||
R.string.notification_summary_message_format,
|
||||
name, channel.getName()));
|
||||
channel.setName(getName(entry));
|
||||
notificationManager.createConversationNotificationChannelForPackage(
|
||||
pkg, appUid, entry.getSbn().getKey(), channel,
|
||||
conversationId);
|
||||
@@ -81,4 +66,19 @@ public class NotificationChannelHelper {
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
private static String getName(NotificationEntry entry) {
|
||||
if (entry.getRanking().getShortcutInfo().getShortLabel() != null) {
|
||||
return entry.getRanking().getShortcutInfo().getShortLabel().toString();
|
||||
}
|
||||
Bundle extras = entry.getSbn().getNotification().extras;
|
||||
String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = extras.getString(Notification.EXTRA_TITLE);
|
||||
}
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = "fallback";
|
||||
}
|
||||
return nameString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1141,6 +1141,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
if (mMenuRow.shouldUseDefaultMenuItems()) {
|
||||
ArrayList<MenuItem> items = new ArrayList<>();
|
||||
items.add(NotificationMenuRow.createConversationItem(mContext));
|
||||
items.add(NotificationMenuRow.createPartialConversationItem(mContext));
|
||||
items.add(NotificationMenuRow.createInfoItem(mContext));
|
||||
items.add(NotificationMenuRow.createSnoozeItem(mContext));
|
||||
items.add(NotificationMenuRow.createAppOpsItem(mContext));
|
||||
|
||||
@@ -1347,11 +1347,11 @@ public class NotificationContentView extends FrameLayout {
|
||||
if (bubbleButton == null || actionContainer == null) {
|
||||
return;
|
||||
}
|
||||
boolean isPerson =
|
||||
boolean isPersonWithShortcut =
|
||||
mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking())
|
||||
!= PeopleNotificationIdentifier.TYPE_NON_PERSON;
|
||||
>= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
|
||||
boolean showButton = isBubblesEnabled()
|
||||
&& isPerson
|
||||
&& isPersonWithShortcut
|
||||
&& entry.getBubbleMetadata() != null;
|
||||
if (showButton) {
|
||||
Drawable d = mContext.getResources().getDrawable(entry.isBubble()
|
||||
|
||||
@@ -97,7 +97,6 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
private String mDelegatePkg;
|
||||
private NotificationChannel mNotificationChannel;
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
private String mConversationId;
|
||||
private StatusBarNotification mSbn;
|
||||
@Nullable private Notification.BubbleMetadata mBubbleMetadata;
|
||||
private Context mUserContext;
|
||||
@@ -233,14 +232,10 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
mBuilderProvider = builderProvider;
|
||||
|
||||
mShortcutManager = shortcutManager;
|
||||
mConversationId = mNotificationChannel.getConversationId();
|
||||
if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) {
|
||||
mConversationId = mSbn.getShortcutId(mContext);
|
||||
}
|
||||
if (TextUtils.isEmpty(mConversationId)) {
|
||||
mShortcutInfo = entry.getRanking().getShortcutInfo();
|
||||
if (mShortcutInfo == null) {
|
||||
throw new IllegalArgumentException("Does not have required information");
|
||||
}
|
||||
mShortcutInfo = entry.getRanking().getShortcutInfo();
|
||||
|
||||
mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded(
|
||||
getContext(), mINotificationManager, entry, mNotificationChannel);
|
||||
@@ -319,31 +314,9 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
|
||||
private void bindIcon(boolean important) {
|
||||
ImageView image = findViewById(R.id.conversation_icon);
|
||||
if (mShortcutInfo != null) {
|
||||
image.setImageDrawable(mIconFactory.getConversationDrawable(
|
||||
mShortcutInfo, mPackageName, mAppUid,
|
||||
important));
|
||||
} else {
|
||||
if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
|
||||
// TODO: maybe use a generic group icon, or a composite of recent senders
|
||||
image.setImageDrawable(mPm.getDefaultActivityIcon());
|
||||
} else {
|
||||
final List<Notification.MessagingStyle.Message> messages =
|
||||
Notification.MessagingStyle.Message.getMessagesFromBundleArray(
|
||||
(Parcelable[]) mSbn.getNotification().extras.get(
|
||||
Notification.EXTRA_MESSAGES));
|
||||
image.setImageDrawable(mIconFactory.getConversationDrawable(
|
||||
mShortcutInfo, mPackageName, mAppUid, important));
|
||||
|
||||
final Notification.MessagingStyle.Message latestMessage =
|
||||
Notification.MessagingStyle.findLatestIncomingMessage(messages);
|
||||
Icon personIcon = latestMessage.getSenderPerson().getIcon();
|
||||
if (personIcon != null) {
|
||||
image.setImageIcon(latestMessage.getSenderPerson().getIcon());
|
||||
} else {
|
||||
// TODO: choose something better
|
||||
image.setImageDrawable(mPm.getDefaultActivityIcon());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindPackage() {
|
||||
|
||||
@@ -252,6 +252,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
} else if (gutsView instanceof NotificationConversationInfo) {
|
||||
initializeConversationNotificationInfo(
|
||||
row, (NotificationConversationInfo) gutsView);
|
||||
} else if (gutsView instanceof PartialConversationInfo) {
|
||||
initializePartialConversationNotificationInfo(row,
|
||||
(PartialConversationInfo) gutsView);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -357,7 +360,47 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the {@link NotificationConversationInfo} inside the notification row's guts.
|
||||
* Sets up the {@link PartialConversationInfo} inside the notification row's guts.
|
||||
* @param row view to set up the guts for
|
||||
* @param notificationInfoView view to set up/bind within {@code row}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void initializePartialConversationNotificationInfo(
|
||||
final ExpandableNotificationRow row,
|
||||
PartialConversationInfo notificationInfoView) throws Exception {
|
||||
NotificationGuts guts = row.getGuts();
|
||||
StatusBarNotification sbn = row.getEntry().getSbn();
|
||||
String packageName = sbn.getPackageName();
|
||||
// Settings link is only valid for notifications that specify a non-system user
|
||||
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
|
||||
UserHandle userHandle = sbn.getUser();
|
||||
PackageManager pmUser = StatusBar.getPackageManagerForUser(
|
||||
mContext, userHandle.getIdentifier());
|
||||
|
||||
if (!userHandle.equals(UserHandle.ALL)
|
||||
|| mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
|
||||
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
|
||||
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
|
||||
guts.resetFalsingCheck();
|
||||
mOnSettingsClickListener.onSettingsClick(sbn.getKey());
|
||||
startAppNotificationSettingsActivity(packageName, appUid, channel, row);
|
||||
};
|
||||
}
|
||||
|
||||
notificationInfoView.bindNotification(
|
||||
pmUser,
|
||||
mNotificationManager,
|
||||
packageName,
|
||||
row.getEntry().getChannel(),
|
||||
row.getUniqueChannels(),
|
||||
row.getEntry(),
|
||||
onSettingsClick,
|
||||
mDeviceProvisionedController.isDeviceProvisioned(),
|
||||
row.getIsNonblockable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the {@link ConversationInfo} inside the notification row's guts.
|
||||
* @param row view to set up the guts for
|
||||
* @param notificationInfoView view to set up/bind within {@code row}
|
||||
*/
|
||||
|
||||
@@ -268,7 +268,9 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
|
||||
NotificationEntry entry = mParent.getEntry();
|
||||
int personNotifType = mPeopleNotificationIdentifier
|
||||
.getPeopleNotificationType(entry.getSbn(), entry.getRanking());
|
||||
if (personNotifType != PeopleNotificationIdentifier.TYPE_NON_PERSON) {
|
||||
if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) {
|
||||
mInfoItem = createPartialConversationItem(mContext);
|
||||
} else if (personNotifType >= PeopleNotificationIdentifier.TYPE_FULL_PERSON) {
|
||||
mInfoItem = createConversationItem(mContext);
|
||||
} else {
|
||||
mInfoItem = createInfoItem(mContext);
|
||||
@@ -667,6 +669,16 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
|
||||
R.drawable.ic_settings);
|
||||
}
|
||||
|
||||
static NotificationMenuItem createPartialConversationItem(Context context) {
|
||||
Resources res = context.getResources();
|
||||
String infoDescription = res.getString(R.string.notification_menu_gear_description);
|
||||
PartialConversationInfo infoContent =
|
||||
(PartialConversationInfo) LayoutInflater.from(context).inflate(
|
||||
R.layout.partial_conversation_info, null, false);
|
||||
return new NotificationMenuItem(context, infoDescription, infoContent,
|
||||
R.drawable.ic_settings);
|
||||
}
|
||||
|
||||
static NotificationMenuItem createInfoItem(Context context) {
|
||||
Resources res = context.getResources();
|
||||
String infoDescription = res.getString(R.string.notification_menu_gear_description);
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||
|
||||
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.transition.ChangeBounds;
|
||||
import android.transition.Fade;
|
||||
import android.transition.TransitionManager;
|
||||
import android.transition.TransitionSet;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The guts of a conversation notification that doesn't use valid shortcuts that is revealed when
|
||||
* performing a long press.
|
||||
*/
|
||||
public class PartialConversationInfo extends LinearLayout implements
|
||||
NotificationGuts.GutsContent {
|
||||
private static final String TAG = "PartialConvoGuts";
|
||||
|
||||
private INotificationManager mINotificationManager;
|
||||
private PackageManager mPm;
|
||||
private String mPackageName;
|
||||
private String mAppName;
|
||||
private int mAppUid;
|
||||
private String mDelegatePkg;
|
||||
private NotificationChannel mNotificationChannel;
|
||||
private StatusBarNotification mSbn;
|
||||
private boolean mIsDeviceProvisioned;
|
||||
private boolean mIsNonBlockable;
|
||||
private Set<NotificationChannel> mUniqueChannelsInRow;
|
||||
private Drawable mPkgIcon;
|
||||
|
||||
private @Action int mSelectedAction = -1;
|
||||
private boolean mPressedApply;
|
||||
private boolean mPresentingChannelEditorDialog = false;
|
||||
|
||||
private NotificationInfo.OnSettingsClickListener mOnSettingsClickListener;
|
||||
private NotificationGuts mGutsContainer;
|
||||
private ChannelEditorDialogController mChannelEditorDialogController;
|
||||
|
||||
@VisibleForTesting
|
||||
boolean mSkipPost = false;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({ACTION_SETTINGS})
|
||||
private @interface Action {}
|
||||
static final int ACTION_SETTINGS = 5;
|
||||
|
||||
private OnClickListener mOnDone = v -> {
|
||||
mPressedApply = true;
|
||||
closeControls(v, true);
|
||||
};
|
||||
|
||||
public PartialConversationInfo(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void bindNotification(
|
||||
PackageManager pm,
|
||||
INotificationManager iNotificationManager,
|
||||
String pkg,
|
||||
NotificationChannel notificationChannel,
|
||||
Set<NotificationChannel> uniqueChannelsInRow,
|
||||
NotificationEntry entry,
|
||||
NotificationInfo.OnSettingsClickListener onSettingsClick,
|
||||
boolean isDeviceProvisioned,
|
||||
boolean isNonBlockable) {
|
||||
mSelectedAction = -1;
|
||||
mINotificationManager = iNotificationManager;
|
||||
mPackageName = pkg;
|
||||
mSbn = entry.getSbn();
|
||||
mPm = pm;
|
||||
mAppName = mPackageName;
|
||||
mOnSettingsClickListener = onSettingsClick;
|
||||
mNotificationChannel = notificationChannel;
|
||||
mAppUid = mSbn.getUid();
|
||||
mDelegatePkg = mSbn.getOpPkg();
|
||||
mIsDeviceProvisioned = isDeviceProvisioned;
|
||||
mIsNonBlockable = isNonBlockable;
|
||||
mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
|
||||
mUniqueChannelsInRow = uniqueChannelsInRow;
|
||||
|
||||
bindHeader();
|
||||
bindActions();
|
||||
|
||||
View turnOffButton = findViewById(R.id.turn_off_notifications);
|
||||
turnOffButton.setOnClickListener(getTurnOffNotificationsClickListener());
|
||||
turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonBlockable
|
||||
? VISIBLE : GONE);
|
||||
|
||||
View done = findViewById(R.id.done);
|
||||
done.setOnClickListener(mOnDone);
|
||||
}
|
||||
|
||||
private void bindActions() {
|
||||
final View settingsButton = findViewById(R.id.info);
|
||||
settingsButton.setOnClickListener(getSettingsOnClickListener());
|
||||
settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
|
||||
|
||||
TextView msg = findViewById(R.id.non_configurable_text);
|
||||
msg.setText(getResources().getString(R.string.no_shortcut, mAppName));
|
||||
}
|
||||
|
||||
private void bindHeader() {
|
||||
bindConversationDetails();
|
||||
|
||||
// Delegate
|
||||
bindDelegate();
|
||||
}
|
||||
|
||||
private OnClickListener getSettingsOnClickListener() {
|
||||
if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
|
||||
final int appUidF = mAppUid;
|
||||
return ((View view) -> {
|
||||
mOnSettingsClickListener.onClick(view, mNotificationChannel, appUidF);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private OnClickListener getTurnOffNotificationsClickListener() {
|
||||
return ((View view) -> {
|
||||
if (!mPresentingChannelEditorDialog && mChannelEditorDialogController != null) {
|
||||
mPresentingChannelEditorDialog = true;
|
||||
|
||||
mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid,
|
||||
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
|
||||
mChannelEditorDialogController.setOnFinishListener(() -> {
|
||||
mPresentingChannelEditorDialog = false;
|
||||
closeControls(this, false);
|
||||
});
|
||||
mChannelEditorDialogController.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void bindConversationDetails() {
|
||||
final TextView channelName = findViewById(R.id.parent_channel_name);
|
||||
channelName.setText(mNotificationChannel.getName());
|
||||
|
||||
bindGroup();
|
||||
bindName();
|
||||
bindPackage();
|
||||
bindIcon();
|
||||
}
|
||||
|
||||
private void bindName() {
|
||||
TextView name = findViewById(R.id.name);
|
||||
Bundle extras = mSbn.getNotification().extras;
|
||||
String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = extras.getString(Notification.EXTRA_TITLE);
|
||||
}
|
||||
name.setText(nameString);
|
||||
}
|
||||
|
||||
private void bindIcon() {
|
||||
ImageView image = findViewById(R.id.conversation_icon);
|
||||
if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
|
||||
// TODO: maybe use a generic group icon, or a composite of recent senders
|
||||
image.setImageDrawable(mPkgIcon);
|
||||
} else {
|
||||
final List<Notification.MessagingStyle.Message> messages =
|
||||
Notification.MessagingStyle.Message.getMessagesFromBundleArray(
|
||||
(Parcelable[]) mSbn.getNotification().extras.get(
|
||||
Notification.EXTRA_MESSAGES));
|
||||
|
||||
final Notification.MessagingStyle.Message latestMessage =
|
||||
Notification.MessagingStyle.findLatestIncomingMessage(messages);
|
||||
Icon personIcon = null;
|
||||
if (latestMessage != null && latestMessage.getSenderPerson() != null) {
|
||||
personIcon = latestMessage.getSenderPerson().getIcon();
|
||||
}
|
||||
if (personIcon != null) {
|
||||
image.setImageIcon(latestMessage.getSenderPerson().getIcon());
|
||||
} else {
|
||||
image.setImageDrawable(mPkgIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindPackage() {
|
||||
ApplicationInfo info;
|
||||
try {
|
||||
info = mPm.getApplicationInfo(
|
||||
mPackageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
| PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
|
||||
if (info != null) {
|
||||
mAppName = String.valueOf(mPm.getApplicationLabel(info));
|
||||
mPkgIcon = mPm.getApplicationIcon(info);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
mPkgIcon = mPm.getDefaultActivityIcon();
|
||||
}
|
||||
((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
|
||||
}
|
||||
|
||||
private void bindDelegate() {
|
||||
TextView delegateView = findViewById(R.id.delegate_name);
|
||||
|
||||
if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
|
||||
// this notification was posted by a delegate!
|
||||
delegateView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
delegateView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindGroup() {
|
||||
// Set group information if this channel has an associated group.
|
||||
CharSequence groupName = null;
|
||||
if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) {
|
||||
try {
|
||||
final NotificationChannelGroup notificationChannelGroup =
|
||||
mINotificationManager.getNotificationChannelGroupForPackage(
|
||||
mNotificationChannel.getGroup(), mPackageName, mAppUid);
|
||||
if (notificationChannelGroup != null) {
|
||||
groupName = notificationChannelGroup.getName();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
TextView groupNameView = findViewById(R.id.group_name);
|
||||
View groupDivider = findViewById(R.id.group_divider);
|
||||
if (groupName != null) {
|
||||
groupNameView.setText(groupName);
|
||||
groupNameView.setVisibility(VISIBLE);
|
||||
groupDivider.setVisibility(VISIBLE);
|
||||
} else {
|
||||
groupNameView.setVisibility(GONE);
|
||||
groupDivider.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean post(Runnable action) {
|
||||
if (mSkipPost) {
|
||||
action.run();
|
||||
return true;
|
||||
} else {
|
||||
return super.post(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedClosing() {
|
||||
// TODO: do we need to do anything here?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
||||
super.onInitializeAccessibilityEvent(event);
|
||||
if (mGutsContainer != null &&
|
||||
event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
||||
if (mGutsContainer.isExposed()) {
|
||||
event.getText().add(mContext.getString(
|
||||
R.string.notification_channel_controls_opened_accessibility, mAppName));
|
||||
} else {
|
||||
event.getText().add(mContext.getString(
|
||||
R.string.notification_channel_controls_closed_accessibility, mAppName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the controls and commits the updated importance values (indirectly).
|
||||
*
|
||||
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
|
||||
* user does not have the ability to undo the action anymore.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void closeControls(View v, boolean save) {
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
mGutsContainer.closeControls(x, y, save, false /* force */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGutsParent(NotificationGuts guts) {
|
||||
mGutsContainer = guts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willBeRemoved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBeSaved() {
|
||||
return mPressedApply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getContentView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleCloseControls(boolean save, boolean force) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualHeight() {
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isAnimating() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -386,7 +386,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
applicationInfo);
|
||||
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
|
||||
|
||||
NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
||||
NotificationEntry entry = new NotificationEntryBuilder()
|
||||
.setSbn(mSbn)
|
||||
.setShortcutInfo(mShortcutInfo)
|
||||
.build();
|
||||
mNotificationInfo.bindNotification(
|
||||
mShortcutManager,
|
||||
mMockPackageManager,
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyBoolean;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.app.Person;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class PartialConversationInfoTest extends SysuiTestCase {
|
||||
private static final String TEST_PACKAGE_NAME = "test_package";
|
||||
private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
|
||||
private static final int TEST_UID = 1;
|
||||
private static final String TEST_CHANNEL = "test_channel";
|
||||
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
|
||||
|
||||
private TestableLooper mTestableLooper;
|
||||
private PartialConversationInfo mInfo;
|
||||
private NotificationChannel mNotificationChannel;
|
||||
private NotificationChannel mDefaultNotificationChannel;
|
||||
private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>();
|
||||
private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>();
|
||||
private StatusBarNotification mSbn;
|
||||
private NotificationEntry mEntry;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Mock
|
||||
private MetricsLogger mMetricsLogger;
|
||||
@Mock
|
||||
private INotificationManager mMockINotificationManager;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Mock
|
||||
private Icon mIcon;
|
||||
@Mock
|
||||
private Drawable mDrawable;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
|
||||
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
|
||||
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
||||
// Inflate the layout
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
|
||||
mInfo = (PartialConversationInfo) layoutInflater.inflate(R.layout.partial_conversation_info,
|
||||
null);
|
||||
mInfo.setGutsParent(mock(NotificationGuts.class));
|
||||
// Our view is never attached to a window so the View#post methods in NotificationInfo never
|
||||
// get called. Setting this will skip the post and do the action immediately.
|
||||
mInfo.mSkipPost = true;
|
||||
|
||||
// PackageManager must return a packageInfo and applicationInfo.
|
||||
final PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = TEST_PACKAGE_NAME;
|
||||
when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(packageInfo);
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.uid = TEST_UID; // non-zero
|
||||
when(mMockPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt())).thenReturn(
|
||||
applicationInfo);
|
||||
final PackageInfo systemPackageInfo = new PackageInfo();
|
||||
systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME;
|
||||
when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(systemPackageInfo);
|
||||
when(mMockPackageManager.getPackageInfo(eq("android"), anyInt()))
|
||||
.thenReturn(packageInfo);
|
||||
|
||||
// Package has one channel by default.
|
||||
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
|
||||
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1);
|
||||
|
||||
when(mIcon.loadDrawable(any())).thenReturn(mDrawable);
|
||||
|
||||
// Some test channels.
|
||||
mNotificationChannel = new NotificationChannel(
|
||||
TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
|
||||
mNotificationChannelSet.add(mNotificationChannel);
|
||||
mDefaultNotificationChannel = new NotificationChannel(
|
||||
NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
|
||||
IMPORTANCE_LOW);
|
||||
mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
|
||||
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||
new Notification(), UserHandle.CURRENT, null, 0);
|
||||
mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SetsTextApplicationName() throws Exception {
|
||||
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView textView = mInfo.findViewById(R.id.pkg_name);
|
||||
assertTrue(textView.getText().toString().contains("App Name"));
|
||||
assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_groupSetsPackageIcon() {
|
||||
mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true);
|
||||
final Drawable iconDrawable = mock(Drawable.class);
|
||||
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
|
||||
.thenReturn(iconDrawable);
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
|
||||
assertEquals(iconDrawable, iconView.getDrawable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_notGroupSetsMessageIcon() {
|
||||
Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME)
|
||||
.setStyle(new Notification.MessagingStyle(
|
||||
new Person.Builder().setName("me").build())
|
||||
.addMessage(new Notification.MessagingStyle.Message("hello", 0,
|
||||
new Person.Builder().setName("friend").setIcon(mIcon).build())))
|
||||
.build();
|
||||
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||
n, UserHandle.CURRENT, null, 0);
|
||||
mEntry.setSbn(mSbn);
|
||||
mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false);
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
|
||||
assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_noDelegate() {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView nameView = mInfo.findViewById(R.id.delegate_name);
|
||||
assertEquals(GONE, nameView.getVisibility());
|
||||
final TextView dividerView = mInfo.findViewById(R.id.group_divider);
|
||||
assertEquals(GONE, dividerView.getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_delegate() throws Exception {
|
||||
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, "other", 0, null, TEST_UID, 0,
|
||||
new Notification(), UserHandle.CURRENT, null, 0);
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.uid = 7; // non-zero
|
||||
when(mMockPackageManager.getApplicationInfo(eq("other"), anyInt())).thenReturn(
|
||||
applicationInfo);
|
||||
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
|
||||
|
||||
NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
entry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView nameView = mInfo.findViewById(R.id.delegate_name);
|
||||
assertEquals(VISIBLE, nameView.getVisibility());
|
||||
assertTrue(nameView.getText().toString().contains("Proxied"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView groupNameView = mInfo.findViewById(R.id.group_name);
|
||||
assertEquals(GONE, groupNameView.getVisibility());
|
||||
final TextView dividerView = mInfo.findViewById(R.id.group_divider);
|
||||
assertEquals(GONE, dividerView.getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SetsGroupNameIfNonNull() throws Exception {
|
||||
mNotificationChannel.setGroup("test_group_id");
|
||||
final NotificationChannelGroup notificationChannelGroup =
|
||||
new NotificationChannelGroup("test_group_id", "Test Group Name");
|
||||
when(mMockINotificationManager.getNotificationChannelGroupForPackage(
|
||||
eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
|
||||
.thenReturn(notificationChannelGroup);
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView groupNameView = mInfo.findViewById(R.id.group_name);
|
||||
assertEquals(View.VISIBLE, groupNameView.getVisibility());
|
||||
assertEquals("Test Group Name", groupNameView.getText());
|
||||
final TextView dividerView = mInfo.findViewById(R.id.group_divider);
|
||||
assertEquals(View.VISIBLE, dividerView.getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SetsTextChannelName() {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final TextView textView = mInfo.findViewById(R.id.parent_channel_name);
|
||||
assertEquals(TEST_CHANNEL_NAME, textView.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SetsOnClickListenerForSettings() {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
(View v, NotificationChannel c, int appUid) -> {
|
||||
assertEquals(mNotificationChannel, c);
|
||||
latch.countDown();
|
||||
},
|
||||
true,
|
||||
false);
|
||||
|
||||
final View settingsButton = mInfo.findViewById(R.id.info);
|
||||
settingsButton.performClick();
|
||||
// Verify that listener was triggered.
|
||||
assertEquals(0, latch.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
final View settingsButton = mInfo.findViewById(R.id.info);
|
||||
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
(View v, NotificationChannel c, int appUid) -> {
|
||||
assertEquals(mNotificationChannel, c);
|
||||
},
|
||||
false,
|
||||
false);
|
||||
final View settingsButton = mInfo.findViewById(R.id.info);
|
||||
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNotification_whenAppUnblockable() {
|
||||
mInfo.bindNotification(
|
||||
mMockPackageManager,
|
||||
mMockINotificationManager,
|
||||
TEST_PACKAGE_NAME,
|
||||
mNotificationChannel,
|
||||
mNotificationChannelSet,
|
||||
mEntry,
|
||||
null,
|
||||
true,
|
||||
true);
|
||||
|
||||
assertEquals(GONE,
|
||||
mInfo.findViewById(R.id.turn_off_notifications).getVisibility());
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor
|
||||
NotificationChannel updatedChannel = mConfig.getConversationNotificationChannel(
|
||||
record.getSbn().getPackageName(),
|
||||
record.getSbn().getUid(), record.getChannel().getId(),
|
||||
record.getSbn().getShortcutId(mContext), true, false);
|
||||
record.getSbn().getShortcutId(), true, false);
|
||||
record.updateNotificationChannel(updatedChannel);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -2718,12 +2718,12 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
return text == null ? null : String.valueOf(text);
|
||||
}
|
||||
|
||||
|
||||
protected void maybeRegisterMessageSent(NotificationRecord r) {
|
||||
Context appContext = r.getSbn().getPackageContext(getContext());
|
||||
Notification.Builder nb =
|
||||
Notification.Builder nb =
|
||||
Notification.Builder.recoverBuilder(appContext, r.getNotification());
|
||||
if (nb.getStyle() instanceof Notification.MessagingStyle) {
|
||||
if (nb.getStyle() instanceof Notification.MessagingStyle && r.getShortcutInfo() == null) {
|
||||
mPreferencesHelper.setMessageSent(r.getSbn().getPackageName(), r.getUid());
|
||||
handleSavePolicyFile();
|
||||
}
|
||||
@@ -5627,7 +5627,7 @@ public class NotificationManagerService extends SystemService {
|
||||
if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
|
||||
channelId = (new Notification.TvExtender(notification)).getChannelId();
|
||||
}
|
||||
String shortcutId = n.getShortcutId(getContext());
|
||||
String shortcutId = n.getShortcutId();
|
||||
final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
|
||||
pkg, notificationUid, channelId, shortcutId,
|
||||
true /* parent ok */, false /* includeDeleted */);
|
||||
|
||||
@@ -1386,10 +1386,6 @@ public final class NotificationRecord {
|
||||
|| !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
|
||||
return false;
|
||||
}
|
||||
if (mShortcutInfo == null && Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 1) {
|
||||
return false;
|
||||
}
|
||||
if (mIsNotConversationOverride) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
private static final String ATT_ENABLED = "enabled";
|
||||
private static final String ATT_USER_ALLOWED = "allowed";
|
||||
private static final String ATT_HIDE_SILENT = "hide_gentle";
|
||||
private static final String ATT_SENT_MESSAGE = "sent_msg";
|
||||
private static final String ATT_SENT_MESSAGE = "sent_invalid_msg";
|
||||
|
||||
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
|
||||
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
|
||||
@@ -194,8 +194,6 @@ public class PreferencesHelper implements RankingConfig {
|
||||
updateBadgingEnabled();
|
||||
updateBubblesEnabled();
|
||||
syncChannelsBypassingDnd(mContext.getUserId());
|
||||
mAllowInvalidShortcuts = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0;
|
||||
}
|
||||
|
||||
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
|
||||
@@ -1313,7 +1311,9 @@ public class PreferencesHelper implements RankingConfig {
|
||||
int N = r.channels.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final NotificationChannel nc = r.channels.valueAt(i);
|
||||
if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()) {
|
||||
if (!TextUtils.isEmpty(nc.getConversationId())
|
||||
&& !nc.isDeleted()
|
||||
&& !nc.isDemoted()) {
|
||||
ConversationChannelWrapper conversation = new ConversationChannelWrapper();
|
||||
conversation.setPkg(r.pkg);
|
||||
conversation.setUid(r.uid);
|
||||
|
||||
@@ -152,9 +152,13 @@ public class ShortcutHelper {
|
||||
if (shortcutInfo == null || !shortcutInfo.isLongLived() || !shortcutInfo.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
return mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
|
||||
// TODO (b/155016294) uncomment when sharing shortcuts are required
|
||||
/*
|
||||
mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
|
||||
shortcutInfo.getPackage(), shortcutInfo.getId(), shortcutInfo.getUserId(),
|
||||
SHARING_FILTER);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,8 +76,6 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testInvalidShortcutFlagEnabled_looksUpCorrectChannel() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
|
||||
|
||||
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
|
||||
extractor.setConfig(mConfig);
|
||||
@@ -96,7 +94,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
|
||||
NotificationChannel updatedChannel =
|
||||
new NotificationChannel("a", "", IMPORTANCE_HIGH);
|
||||
when(mConfig.getConversationNotificationChannel(
|
||||
any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)),
|
||||
any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId()),
|
||||
eq(true), eq(false)))
|
||||
.thenReturn(updatedChannel);
|
||||
|
||||
@@ -106,8 +104,6 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
|
||||
|
||||
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
|
||||
extractor.setConfig(mConfig);
|
||||
|
||||
@@ -6589,14 +6589,45 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordMessages() throws RemoteException {
|
||||
public void testRecordMessages_invalidMsg() throws RemoteException {
|
||||
NotificationRecord nr =
|
||||
generateMessageBubbleNotifRecord(mTestNotificationChannel,
|
||||
"testRecordMessages");
|
||||
"testRecordMessages_invalidMsg");
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
assertTrue(mBinderService.hasSentMessage(PKG, mUid));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordMessages_validMsg() throws RemoteException {
|
||||
// Messaging notification with shortcut info
|
||||
Notification.BubbleMetadata metadata =
|
||||
new Notification.BubbleMetadata.Builder("id").build();
|
||||
Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
|
||||
null /* groupKey */, false /* isSummary */);
|
||||
nb.setShortcutId("id");
|
||||
nb.setBubbleMetadata(metadata);
|
||||
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
|
||||
"testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
|
||||
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
// Pretend the shortcut exists
|
||||
List<ShortcutInfo> shortcutInfos = new ArrayList<>();
|
||||
ShortcutInfo info = mock(ShortcutInfo.class);
|
||||
when(info.getPackage()).thenReturn(PKG);
|
||||
when(info.getId()).thenReturn("id");
|
||||
when(info.getUserId()).thenReturn(USER_SYSTEM);
|
||||
when(info.isLongLived()).thenReturn(true);
|
||||
when(info.isEnabled()).thenReturn(true);
|
||||
shortcutInfos.add(info);
|
||||
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
assertFalse(mBinderService.hasSentMessage(PKG, mUid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,6 @@ public class NotificationRecordTest extends UiServiceTestCase {
|
||||
when(mMockContext.getResources()).thenReturn(getContext().getResources());
|
||||
when(mMockContext.getPackageManager()).thenReturn(mPm);
|
||||
when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.targetSdkVersion = Build.VERSION_CODES.O;
|
||||
when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
|
||||
@@ -1127,18 +1125,7 @@ public class NotificationRecordTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsConversation_nullShortcut() {
|
||||
StatusBarNotification sbn = getMessagingStyleNotification();
|
||||
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
|
||||
record.setShortcutInfo(null);
|
||||
|
||||
assertFalse(record.isConversation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsConversation_bypassShortcutFlagEnabled() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
|
||||
public void testIsConversation_noShortcut() {
|
||||
StatusBarNotification sbn = getMessagingStyleNotification();
|
||||
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
|
||||
record.setShortcutInfo(null);
|
||||
|
||||
@@ -3022,32 +3022,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaceholderConversationId_shortcutNotRequired() throws Exception {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
|
||||
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
|
||||
mAppOpsManager);
|
||||
|
||||
final String xml = "<ranking version=\"1\">\n"
|
||||
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
|
||||
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
|
||||
+ "</package>"
|
||||
+ "</ranking>";
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
|
||||
null);
|
||||
parser.nextTag();
|
||||
mHelper.readXml(parser, false, UserHandle.USER_ALL);
|
||||
|
||||
assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaceholderConversationId_shortcutRequired() throws Exception {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
|
||||
mAppOpsManager);
|
||||
|
||||
@@ -3067,8 +3043,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testNormalConversationId_shortcutRequired() throws Exception {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
|
||||
mAppOpsManager);
|
||||
|
||||
@@ -3088,8 +3062,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testNoConversationId_shortcutRequired() throws Exception {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
|
||||
mAppOpsManager);
|
||||
|
||||
@@ -3275,6 +3247,19 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConversations_noDemoted() {
|
||||
NotificationChannel parent = new NotificationChannel("parent", "p", 1);
|
||||
mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
|
||||
NotificationChannel channel =
|
||||
new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
|
||||
channel.setConversationId("parent", "convo");
|
||||
channel.setDemoted(true);
|
||||
mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
|
||||
|
||||
assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConversations() {
|
||||
NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
|
||||
|
||||
@@ -40,6 +40,7 @@ import androidx.test.runner.AndroidJUnit4;
|
||||
import com.android.server.UiServiceTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -184,6 +185,7 @@ public class ShortcutHelperTest extends UiServiceTestCase {
|
||||
assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isNull();
|
||||
}
|
||||
|
||||
@Ignore("b/155016294")
|
||||
@Test
|
||||
public void testGetValidShortcutInfo_notSharingShortcut() {
|
||||
ShortcutInfo si = mock(ShortcutInfo.class);
|
||||
@@ -229,8 +231,9 @@ public class ShortcutHelperTest extends UiServiceTestCase {
|
||||
ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
|
||||
shortcuts.add(si);
|
||||
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts);
|
||||
when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
|
||||
anyString(), anyInt(), any())).thenReturn(true);
|
||||
// TODO: b/155016294
|
||||
//when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
|
||||
// anyString(), anyInt(), any())).thenReturn(true);
|
||||
|
||||
assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isSameAs(si);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user