Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2488e2b6 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Use collapsable preferences for channel lists" into main

parents fdfc5344 3532044b
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -49,12 +49,7 @@
    <!-- Channels/Channel groups added here -->
    <PreferenceCategory
        android:key="channels"
        android:layout="@layout/empty_view" />

    <Preference
        android:key="more"
        android:title="@string/no_recent_channels"
        android:icon="@drawable/ic_expand"/>
        android:title="@string/notification_channels" />

    <PreferenceCategory
        android:key="pre_channels_fields"
+5 −5
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 * Copyright (C) 2025 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.
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.settings.notification.modes;
package com.android.settings.notification;

import android.util.Log;

@@ -28,11 +28,11 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

class FutureUtil {
public class FutureUtil {

    private static final String TAG = "ZenFutureUtil";
    private static final String TAG = "FutureUtil";

    static <V> void whenDone(ListenableFuture<V> future, Consumer<V> consumer, Executor executor) {
    public static <V> void whenDone(ListenableFuture<V> future, Consumer<V> consumer, Executor executor) {
        whenDone(future, consumer, executor, "Error in future");
    }

+1 −1
Original line number Diff line number Diff line
@@ -865,7 +865,7 @@ public class NotificationBackend {
        public int userId;
        public int blockedChannelCount;
        public int channelCount;
        public Map<String, NotificationsSentState> sentByChannel;
        public Map<String, NotificationsSentState> sentByChannel = new HashMap<>();
        public NotificationsSentState sentByApp;
        public boolean showAllChannels = true;
        public boolean canBePromoted;
+2 −3
Original line number Diff line number Diff line
@@ -122,14 +122,13 @@ public class AppNotificationSettings extends NotificationSettings {
                mBackend));
        mControllers.add(new DndPreferenceController(context, mBackend));
        mControllers.add(new AppLinkPreferenceController(context));
        mControllers.add(new ChannelListPreferenceController(context, mBackend));
        mControllers.add(new ChannelListPreferenceController(
                context, mDependentFieldListener, mBackend));
        mControllers.add(new AppConversationListPreferenceController(context, mBackend));
        mControllers.add(new InvalidConversationInfoPreferenceController(context, mBackend));
        mControllers.add(new InvalidConversationPreferenceController(context, mBackend));
        mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
        mControllers.add(new NotificationsOffPreferenceController(context));
        mControllers.add(new ShowMorePreferenceController(
                context, mDependentFieldListener, mBackend));
        mControllers.add(new BundleListPreferenceController(context, mBackend));
        mControllers.add(new PromotedNotificationsPreferenceController(context, mBackend));
        mControllers.add(new AdjustmentKeyPreferenceController(context, mBackend,
+93 −68
Original line number Diff line number Diff line
@@ -24,13 +24,13 @@ import android.app.NotificationChannelGroup;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
@@ -40,13 +40,21 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.FutureUtil;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.ExpandablePreference;

import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

public class ChannelListPreferenceController extends NotificationPreferenceController {

@@ -54,13 +62,30 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
    private static final String KEY_GENERAL_CATEGORY = "categories";
    private static final String KEY_ZERO_CATEGORIES = "zeroCategories";
    public static final String ARG_FROM_SETTINGS = "fromSettings";
    public static final String KEY_SHOW_MORE = "show_more";

    private List<NotificationChannelGroup> mChannelGroupList;
    private PreferenceCategory mPreference;
    int mChannelCount;

    public ChannelListPreferenceController(Context context, NotificationBackend backend) {
    private int mChannelCount;
    private int mVisibleChannelCount;
    private final NotificationSettings.DependentFieldListener mDependentFieldListener;
    private ListeningExecutorService mBackgroundExecutor;
    private Executor mUiExecutor;

    public ChannelListPreferenceController(Context context,
            NotificationSettings.DependentFieldListener dependentFieldListener,
            NotificationBackend backend) {
        super(context, backend);
        mDependentFieldListener = dependentFieldListener;
        mBackgroundExecutor = ThreadUtils.getBackgroundExecutor();
        mUiExecutor = context.getMainExecutor();
    }

    @VisibleForTesting
    void setExecutors(ListeningExecutorService backgroundExecutor,
            Executor uiExecutor) {
        mBackgroundExecutor = MoreExecutors.listeningDecorator(backgroundExecutor);
        mUiExecutor = uiExecutor;
    }

    @Override
@@ -93,68 +118,69 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
    @Override
    public void updateState(Preference preference) {
        mPreference = (PreferenceCategory) preference;
        // Load channel settings
        new AsyncTask<Void, Void, Void>() {
        FutureUtil.whenDone(mBackgroundExecutor.submit(this::loadChannels),
                new Consumer<>() {
                    @Override
            protected Void doInBackground(Void... unused) {
                    public void accept(Boolean aBoolean) {
                        updateFullList();
                    }
                },
                mUiExecutor);
    }

    private boolean loadChannels() {
        mChannelCount = mBackend.getChannelCount(mAppRow.pkg, mAppRow.uid);
        if (mAppRow.showAllChannels) {
            mChannelGroupList = mBackend.getGroups(mAppRow.pkg, mAppRow.uid).getList();
            mVisibleChannelCount = mChannelCount;
        } else {
            mChannelGroupList = mBackend.getGroupsWithRecentBlockedFilter(mAppRow.pkg,
                    mAppRow.uid).getList();
            mVisibleChannelCount = 0;
            for (NotificationChannelGroup group : mChannelGroupList) {
                    mVisibleChannelCount += group.getChannels().size();
            }

                mChannelCount = mBackend.getChannelCount(mAppRow.pkg, mAppRow.uid);
                Collections.sort(mChannelGroupList, CHANNEL_GROUP_COMPARATOR);
                return null;
        }

            @Override
            protected void onPostExecute(Void unused) {
                if (mContext == null) {
                    return;
                }

                updateFullList(mPreference, mChannelGroupList);
            }
        }.execute();
        mChannelGroupList.sort(CHANNEL_GROUP_COMPARATOR);
        return true;
    }

    /**
     * Update the preferences group to match the
     * @param groupPrefsList
     * @param channelGroups
     * Update the preferences group to match the backing data
     */
    void updateFullList(@NonNull PreferenceCategory groupPrefsList,
                @NonNull List<NotificationChannelGroup> channelGroups) {
        if (channelGroups.isEmpty()) {
            if (mChannelCount > 0) {
                groupPrefsList.removeAll();
            } else {
                if (groupPrefsList.getPreferenceCount() == 1
                        && KEY_ZERO_CATEGORIES.equals(groupPrefsList.getPreference(0).getKey())) {
                    // Ensure the titles are correct for the current language, but otherwise leave alone
                    PreferenceGroup groupCategory = (PreferenceGroup) groupPrefsList.getPreference(
                            0);
                    groupCategory.setTitle(R.string.notification_channels);
                    groupCategory.getPreference(0).setTitle(R.string.no_channels);
                } else {
                    // Clear any contents and create the 'zero-categories' group.
                    groupPrefsList.removeAll();

                    PreferenceCategory groupCategory = new PreferenceCategory(mContext);
                    groupCategory.setTitle(R.string.notification_channels);
                    groupCategory.setKey(KEY_ZERO_CATEGORIES);
                    groupPrefsList.addPreference(groupCategory);

                    Preference empty = new Preference(mContext);
    void updateFullList() {
        Preference empty = mPreference.findPreference(KEY_ZERO_CATEGORIES);
        if (mChannelCount == 0) {
            if (empty == null) {
                mPreference.removeAll();
                empty = new Preference(mContext);
                empty.setTitle(R.string.no_channels);
                    empty.setEnabled(false);
                    groupCategory.addPreference(empty);
                empty.setKey(KEY_ZERO_CATEGORIES);
                mPreference.addPreference(empty);
            }
        } else if (empty != null) {
            mPreference.removePreference(empty);
        }
        } else {
            updateGroupList(groupPrefsList, channelGroups);

        if (!mChannelGroupList.isEmpty()) {
            updateGroupList(mPreference, mChannelGroupList);
        }
        Preference showMore = mPreference.findPreference(KEY_SHOW_MORE);
        if (!mAppRow.showAllChannels && mVisibleChannelCount != mChannelCount) {
            if (showMore == null) {
                showMore = new Preference(mContext);
                showMore.setKey(KEY_SHOW_MORE);
                showMore.setTitle(R.string.no_recent_channels);
                showMore.setOnPreferenceClickListener(preference1 -> {
                    mAppRow.showAllChannels = true;
                    mDependentFieldListener.onFieldValueChanged();
                    return true;
                });
                mPreference.addPreference(showMore);
            }
        } else if (showMore != null) {
            mPreference.removePreference(showMore);
        }
    }

@@ -163,7 +189,7 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
     * match, it checks all groups, and if it can't find that group anywhere, it creates it.
     */
    @NonNull
    private PreferenceCategory findOrCreateGroupCategoryForKey(
    private ExpandablePreference findOrCreateGroupCategoryForKey(
            @NonNull PreferenceCategory groupPrefsList, @Nullable String key, int expectedIndex) {
        if (key == null) {
            key = KEY_GENERAL_CATEGORY;
@@ -172,17 +198,17 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
        if (expectedIndex < preferenceCount) {
            Preference preference = groupPrefsList.getPreference(expectedIndex);
            if (key.equals(preference.getKey())) {
                return (PreferenceCategory) preference;
                return (ExpandablePreference) preference;
            }
        }
        for (int i = 0; i < preferenceCount; i++) {
            Preference preference = groupPrefsList.getPreference(i);
            if (key.equals(preference.getKey())) {
                preference.setOrder(expectedIndex);
                return (PreferenceCategory) preference;
                return (ExpandablePreference) preference;
            }
        }
        PreferenceCategory groupCategory = new PreferenceCategory(mContext);
        ExpandablePreference groupCategory = new ExpandablePreference(mContext);
        groupCategory.setOrder(expectedIndex);
        groupCategory.setKey(key);
        groupPrefsList.addPreference(groupCategory);
@@ -194,10 +220,10 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
        // Update the list, but optimize for the most common case where the list hasn't changed.
        int numFinalGroups = channelGroups.size();
        int initialPrefCount = groupPrefsList.getPreferenceCount();
        List<PreferenceCategory> finalOrderedGroups = new ArrayList<>(numFinalGroups);
        List<ExpandablePreference> finalOrderedGroups = new ArrayList<>(numFinalGroups);
        for (int i = 0; i < numFinalGroups; i++) {
            NotificationChannelGroup group = channelGroups.get(i);
            PreferenceCategory groupCategory =
            ExpandablePreference groupCategory =
                    findOrCreateGroupCategoryForKey(groupPrefsList, group.getId(), i);
            finalOrderedGroups.add(groupCategory);
            updateGroupPreferences(group, groupCategory);
@@ -211,14 +237,13 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
        boolean requiresRemoval = postAddPrefCount != numFinalGroups;
        if (hasInsertions || requiresRemoval) {
            groupPrefsList.removeAll();
            for (PreferenceCategory group : finalOrderedGroups) {
            for (ExpandablePreference group : finalOrderedGroups) {
                groupPrefsList.addPreference(group);
            }
        }
        Preference otherGroup = groupPrefsList.findPreference(KEY_GENERAL_CATEGORY);
        ExpandablePreference otherGroup = groupPrefsList.findPreference(KEY_GENERAL_CATEGORY);
        if (otherGroup != null) {
            otherGroup.setTitle(numFinalGroups == 1
                    ? R.string.notification_channels : R.string.notification_channels_other);
            otherGroup.setTitle(R.string.notification_channels_other);
        }
    }

Loading