| /* |
| * 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.settings.notification; |
| |
| import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE; |
| import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; |
| import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; |
| import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; |
| |
| import android.annotation.Nullable; |
| import android.app.NotificationChannel; |
| import android.app.NotificationChannelGroup; |
| import android.content.Context; |
| import android.content.pm.ShortcutInfo; |
| import android.graphics.drawable.Drawable; |
| import android.service.notification.ConversationChannelWrapper; |
| import android.view.View; |
| import android.widget.ImageView; |
| |
| import androidx.preference.Preference; |
| import androidx.preference.PreferenceCategory; |
| import androidx.preference.PreferenceViewHolder; |
| |
| import com.android.settings.R; |
| import com.android.settings.notification.app.AppConversationListPreferenceController; |
| import com.android.settingslib.RestrictedLockUtils; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| /** |
| * Displays a list of conversations that have either been selected or excluded from bubbling. |
| */ |
| public class AppBubbleListPreferenceController extends AppConversationListPreferenceController { |
| |
| private static final String KEY = "bubble_conversations"; |
| |
| public AppBubbleListPreferenceController(Context context, NotificationBackend backend) { |
| super(context, backend); |
| } |
| |
| @Override |
| public void updateState(Preference preference) { |
| // loading convos is async; hide header until we know we have conversations to show |
| preference.setVisible(false); |
| super.updateState(preference); |
| } |
| |
| @Override |
| public void onResume(NotificationBackend.AppRow appRow, |
| @Nullable NotificationChannel channel, @Nullable NotificationChannelGroup group, |
| Drawable conversationDrawable, |
| ShortcutInfo conversationInfo, |
| RestrictedLockUtils.EnforcedAdmin admin) { |
| super.onResume(appRow, channel, group, conversationDrawable, conversationInfo, admin); |
| // In case something changed in the foreground (e.g. via bubble button on notification) |
| loadConversationsAndPopulate(); |
| } |
| |
| @Override |
| public String getPreferenceKey() { |
| return KEY; |
| } |
| |
| @Override |
| public boolean isAvailable() { |
| // copy rather than inherit super's isAvailable because apps can link to this page |
| // as part of onboarding, before they send a valid conversation notification |
| if (mAppRow == null) { |
| return false; |
| } |
| if (mAppRow.banned) { |
| return false; |
| } |
| if (mChannel != null) { |
| if (mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid) |
| || NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())) { |
| return false; |
| } |
| } |
| if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_NONE) { |
| return false; |
| } |
| return true; |
| } |
| |
| @VisibleForTesting |
| @Override |
| public List<ConversationChannelWrapper> filterAndSortConversations( |
| List<ConversationChannelWrapper> conversations) { |
| return conversations.stream() |
| .sorted(mConversationComparator) |
| .filter((c) -> { |
| if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_SELECTED) { |
| return c.getNotificationChannel().canBubble(); |
| } else if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_ALL) { |
| return c.getNotificationChannel().getAllowBubbles() == 0; |
| } |
| return false; |
| }) |
| .collect(Collectors.toList()); |
| } |
| |
| @Override |
| protected int getTitleResId() { |
| // TODO: possible to left align like mocks? |
| return mAppRow.bubblePreference == BUBBLE_PREFERENCE_SELECTED |
| ? R.string.bubble_app_setting_selected_conversation_title |
| : R.string.bubble_app_setting_excluded_conversation_title; |
| } |
| |
| @VisibleForTesting |
| @Override |
| public Preference createConversationPref(final ConversationChannelWrapper conversation) { |
| final ConversationPreference pref = new ConversationPreference(mContext); |
| populateConversationPreference(conversation, pref); |
| pref.setOnClickBubblesConversation(mAppRow.bubblePreference == BUBBLE_PREFERENCE_ALL); |
| pref.setOnClickListener((v) -> { |
| conversation.getNotificationChannel().setAllowBubbles(DEFAULT_ALLOW_BUBBLE); |
| mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, conversation.getNotificationChannel()); |
| mPreference.removePreference(pref); |
| if (mPreference.getPreferenceCount() == 0) { |
| mPreference.setVisible(false); |
| } |
| }); |
| return pref; |
| } |
| |
| @Override |
| protected void populateList() { |
| super.populateList(); |
| if (mPreference == null) { |
| return; |
| } |
| mPreference.setVisible(mPreference.getPreferenceCount() > 0); |
| } |
| |
| /** Simple preference with a 'x' button at the end. */ |
| @VisibleForTesting |
| public static class ConversationPreference extends Preference implements View.OnClickListener { |
| |
| View.OnClickListener mOnClickListener; |
| boolean mOnClickBubbles; |
| |
| ConversationPreference(Context context) { |
| super(context); |
| setWidgetLayoutResource(R.layout.bubble_conversation_remove_button); |
| } |
| |
| @Override |
| public void onBindViewHolder(final PreferenceViewHolder holder) { |
| super.onBindViewHolder(holder); |
| ImageView view = holder.itemView.findViewById(R.id.button); |
| view.setContentDescription(mOnClickBubbles |
| ? getContext().getString(R.string.bubble_app_setting_bubble_conversation) |
| : getContext().getString(R.string.bubble_app_setting_unbubble_conversation)); |
| view.setOnClickListener(mOnClickListener); |
| } |
| |
| public void setOnClickBubblesConversation(boolean enablesBubbles) { |
| mOnClickBubbles = enablesBubbles; |
| } |
| |
| public void setOnClickListener(View.OnClickListener listener) { |
| mOnClickListener = listener; |
| } |
| |
| @Override |
| public void onClick(View v) { |
| if (mOnClickListener != null) { |
| mOnClickListener.onClick(v); |
| } |
| } |
| } |
| } |