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

Commit bd369cfe authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Fix Conversation page flickers

In this page, 3 conversation lists are implemented by the
ConversationListPreferenceController, these lists updates its contents
in updateState(), which is after the preference screen view created.
So when the first time this page is showed, animations of added contents
will be shown.

The improvement is when the first time, update the list in the
onCreate(), which is called before view creation, instead of the
updateState().

And also do the same thing for RecentConversationsPreferenceController.

Also, to reduce latency,
1. Because currently there are duplicated calls in
NoConversationsPreferenceController to check whether conversations are
exists or not, by removing the duplicated calls and reuse the result
from other controllers, the latency could be reduced.
2. Currently, there are seperated api calls, the
mBackend.getConversations(false) in AllConversationsPreferenceController
and the mBackend.getConversations(true) in
PriorityConversationsPreferenceController, use one
mBackend.getConversations(false) in ConversationListSettings to improve,
this does not change the behavior because the result is filtered in
matchesFilter() both before and after.
3. Currently, we sort conversations first then filter them, change to
filter first then sort to reduce latency.

Fix: 215073227
Test: visual check & robo tests
Change-Id: I028a7fabbbf64cf5627e6615372282a36eb784e5
parent fa878f2f
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -15,12 +15,10 @@
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/onboarding"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_gravity="center"
              android:gravity="center"
              android:visibility="gone"
              android:orientation="vertical">

    <ImageView
+1 −25
Original line number Diff line number Diff line
@@ -17,26 +17,18 @@
package com.android.settings.notification.app;

import android.content.Context;
import android.os.AsyncTask;
import android.service.notification.ConversationChannelWrapper;

import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;

import java.util.Collections;
import java.util.List;

public class AllConversationsPreferenceController extends ConversationListPreferenceController {

    private static final String KEY = "other_conversations";

    private List<ConversationChannelWrapper> mConversations;

    public AllConversationsPreferenceController(Context context,
            NotificationBackend backend) {
    public AllConversationsPreferenceController(Context context, NotificationBackend backend) {
        super(context, backend);
    }

@@ -45,11 +37,6 @@ public class AllConversationsPreferenceController extends ConversationListPrefer
        return KEY;
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    Preference getSummaryPreference() {
        Preference pref = new Preference(mContext);
@@ -63,15 +50,4 @@ public class AllConversationsPreferenceController extends ConversationListPrefer
    boolean matchesFilter(ConversationChannelWrapper conversation) {
        return !conversation.getNotificationChannel().isImportantConversation();
    }

    @Override
    public void updateState(Preference preference) {
        PreferenceCategory pref = (PreferenceCategory) preference;
        // Load conversations

        mConversations = mBackend.getConversations(false).getList();
        Collections.sort(mConversations, mConversationComparator);

        populateList(mConversations, pref);
    }
}
+39 −24
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.text.TextUtils;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
@@ -38,14 +40,15 @@ import com.android.settingslib.widget.AppPreference;
import java.text.Collator;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class ConversationListPreferenceController extends AbstractPreferenceController {

    private static final String SUMMARY_KEY_SUFFIX = "_summary";
    protected final NotificationBackend mBackend;
    private PreferenceGroup mPreferenceGroup;

    public ConversationListPreferenceController(Context context,
            NotificationBackend backend) {
    public ConversationListPreferenceController(Context context, NotificationBackend backend) {
        super(context);
        mBackend = backend;
    }
@@ -55,44 +58,55 @@ public abstract class ConversationListPreferenceController extends AbstractPrefe
        return true;
    }

    protected void populateList(List<ConversationChannelWrapper> conversations,
            PreferenceGroup containerGroup) {
        containerGroup.setVisible(false);
        containerGroup.removeAll();
    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreferenceGroup = screen.findPreference(getPreferenceKey());
    }

    /**
     * Updates the conversation list.
     * @return true if this controller has content to display.
     */
    boolean updateList(List<ConversationChannelWrapper> conversations) {
        mPreferenceGroup.setVisible(false);
        mPreferenceGroup.removeAll();
        if (conversations != null) {
            populateConversations(conversations, containerGroup);
            populateConversations(conversations);
        }

        if (containerGroup.getPreferenceCount() != 0) {
        boolean hasContent = mPreferenceGroup.getPreferenceCount() != 0;
        if (hasContent) {
            Preference summaryPref = getSummaryPreference();
            if (summaryPref != null) {
                summaryPref.setKey(getPreferenceKey() + SUMMARY_KEY_SUFFIX);
                containerGroup.addPreference(summaryPref);
                mPreferenceGroup.addPreference(summaryPref);
            }
            containerGroup.setVisible(true);
            mPreferenceGroup.setVisible(true);
        }
        return hasContent;
    }

    abstract Preference getSummaryPreference();

    abstract boolean matchesFilter(ConversationChannelWrapper conversation);

    protected void populateConversations(List<ConversationChannelWrapper> conversations,
            PreferenceGroup containerGroup) {
        int order = 100;
        for (ConversationChannelWrapper conversation : conversations) {
            if (conversation.getNotificationChannel().isDemoted()
                    || !matchesFilter(conversation)) {
                continue;
            }
            containerGroup.addPreference(createConversationPref(conversation, order++));
        }
    @VisibleForTesting
    void populateConversations(List<ConversationChannelWrapper> conversations) {
        AtomicInteger order = new AtomicInteger(100);
        conversations.stream()
                .filter(conversation -> !conversation.getNotificationChannel().isDemoted()
                        && matchesFilter(conversation))
                .sorted(mConversationComparator)
                .map(this::createConversationPref)
                .forEachOrdered(preference -> {
                    preference.setOrder(order.getAndIncrement());
                    mPreferenceGroup.addPreference(preference);
                });
    }

    protected Preference createConversationPref(final ConversationChannelWrapper conversation,
            int order) {
    private Preference createConversationPref(final ConversationChannelWrapper conversation) {
        AppPreference pref = new AppPreference(mContext);
        pref.setOrder(order);

        pref.setTitle(getTitle(conversation));
        pref.setSummary(getSummary(conversation));
@@ -141,7 +155,8 @@ public abstract class ConversationListPreferenceController extends AbstractPrefe
                .setSourceMetricsCategory(SettingsEnums.NOTIFICATION_CONVERSATION_LIST_SETTINGS);
    }

    protected Comparator<ConversationChannelWrapper> mConversationComparator =
    @VisibleForTesting
    Comparator<ConversationChannelWrapper> mConversationComparator =
            new Comparator<ConversationChannelWrapper>() {
                private final Collator sCollator = Collator.getInstance();
                @Override
+44 −6
Original line number Diff line number Diff line
@@ -19,8 +19,9 @@ package com.android.settings.notification.app;
import android.app.people.IPeopleManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.ServiceManager;
import android.util.Log;
import android.service.notification.ConversationChannelWrapper;

import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -32,12 +33,16 @@ import java.util.List;

public class ConversationListSettings extends DashboardFragment {
    private static final String TAG = "ConvoListSettings";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    NotificationBackend mBackend = new NotificationBackend();
    IPeopleManager mPs;

    protected List<AbstractPreferenceController> mControllers = new ArrayList<>();
    private NoConversationsPreferenceController mNoConversationsController;
    private PriorityConversationsPreferenceController mPriorityConversationsController;
    private AllConversationsPreferenceController mAllConversationsController;
    private RecentConversationsPreferenceController mRecentConversationsController;
    private boolean mUpdatedInOnCreate = false;

    public ConversationListSettings() {
        mPs = IPeopleManager.Stub.asInterface(
@@ -62,10 +67,43 @@ public class ConversationListSettings extends DashboardFragment {
    @Override
    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
        mControllers = new ArrayList<>();
        mControllers.add(new NoConversationsPreferenceController(context, mBackend, mPs));
        mControllers.add(new PriorityConversationsPreferenceController(context, mBackend));
        mControllers.add(new AllConversationsPreferenceController(context, mBackend));
        mControllers.add(new RecentConversationsPreferenceController(context, mBackend, mPs));
        mNoConversationsController = new NoConversationsPreferenceController(context);
        mControllers.add(mNoConversationsController);
        mPriorityConversationsController =
                new PriorityConversationsPreferenceController(context, mBackend);
        mControllers.add(mPriorityConversationsController);
        mAllConversationsController = new AllConversationsPreferenceController(context, mBackend);
        mControllers.add(mAllConversationsController);
        mRecentConversationsController =
                new RecentConversationsPreferenceController(context, mBackend, mPs);
        mControllers.add(mRecentConversationsController);
        return new ArrayList<>(mControllers);
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        update();
        mUpdatedInOnCreate = true;
    }

    @Override
    public void onStart() {
        super.onStart();
        if (mUpdatedInOnCreate) {
            mUpdatedInOnCreate = false;
        } else {
            update();
        }
    }

    private void update() {
        List<ConversationChannelWrapper> conversationList =
                mBackend.getConversations(false).getList();
        boolean hasContent = mPriorityConversationsController.updateList(conversationList)
                | mAllConversationsController.updateList(conversationList)
                | mRecentConversationsController.updateList();
        mNoConversationsController.setAvailable(!hasContent);
        mNoConversationsController.displayPreference(getPreferenceScreen());
    }
}
+8 −56
Original line number Diff line number Diff line
@@ -16,32 +16,18 @@

package com.android.settings.notification.app;

import android.app.people.IPeopleManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.service.notification.ConversationChannelWrapper;
import android.util.Log;
import android.view.View;

import androidx.preference.Preference;
import com.android.settingslib.core.AbstractPreferenceController;

import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.widget.LayoutPreference;
class NoConversationsPreferenceController extends AbstractPreferenceController {

public class NoConversationsPreferenceController extends ConversationListPreferenceController {

    private static String TAG = "NoConversationsPC";
    private static final String KEY = "no_conversations";

    private IPeopleManager mPs;
    private int mConversationCount = 0;
    private boolean mIsAvailable = false;

    public NoConversationsPreferenceController(Context context,
            NotificationBackend backend, IPeopleManager ps) {
        super(context, backend);
        mPs = ps;
    NoConversationsPreferenceController(Context context) {
        super(context);
    }

    @Override
@@ -51,44 +37,10 @@ public class NoConversationsPreferenceController extends ConversationListPrefere

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    Preference getSummaryPreference() {
        return null;
        return mIsAvailable;
    }

    @Override
    boolean matchesFilter(ConversationChannelWrapper conversation) {
        return false;
    }

    @Override
    public void updateState(Preference preference) {
        LayoutPreference pref = (LayoutPreference) preference;
        // Load conversations
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... unused) {
                mConversationCount = mBackend.getConversations(false).getList().size();
                try {
                    mConversationCount += mPs.getRecentConversations().getList().size();
                } catch (RemoteException e) {
                    Log.w(TAG, "Error calling PS", e);
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void unused) {
                if (mContext == null) {
                    return;
                }
                pref.findViewById(R.id.onboarding).setVisibility(mConversationCount == 0
                        ? View.VISIBLE : View.GONE);
                preference.setVisible(mConversationCount == 0);
            }
        }.execute();
    void setAvailable(boolean available) {
        mIsAvailable = available;
    }
}
Loading