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

Commit a5b620e7 authored by Fan Zhang's avatar Fan Zhang
Browse files

Swipe to dismiss suggestions

- Move dismiss suggestion logic into feature provider
- In DashboardData, use hashcode as suggestion's stable id. This is much
  more likely to provide a truely stable id for each suggestion card.
  Eventually I want to use hash for all tiles to provide stable id.
- Add a SuggestionDismissionController to handle swipe to dismiss
  callbacks

Change-Id: If3770f07a90c5469a0b86fc28f3eb5e4c17227cd
Fix: 35159816
Test: make RunSettingsRoboTests
parent 5e2545c3
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -55,11 +55,4 @@

    </RelativeLayout>

    <ImageView
        android:id="@+id/overflow"
        style="?android:attr/actionOverflowButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"/>

</LinearLayout>
 No newline at end of file
+0 −4
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -39,7 +38,6 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.text.format.Formatter;
import android.util.Log;
import android.util.MutableInt;
import android.view.View;
@@ -51,8 +49,6 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.Callbacks;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
+21 −57
Original line number Diff line number Diff line
@@ -17,21 +17,17 @@ package com.android.settings.dashboard;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -43,18 +39,17 @@ import com.android.settings.SettingsActivity;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.SuggestionParser;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder>
        implements SummaryLoader.SummaryConsumer {
        implements SummaryLoader.SummaryConsumer, SuggestionDismissController.Callback {
    public static final String TAG = "DashboardAdapter";
    private static final String STATE_SUGGESTION_LIST = "suggestion_list";
    private static final String STATE_CATEGORY_LIST = "category_list";
@@ -66,7 +61,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
    private final MetricsFeatureProvider mMetricsFeatureProvider;
    private final DashboardFeatureProvider mDashboardFeatureProvider;
    private final ArrayList<String> mSuggestionsShownLogged;
    private SuggestionParser mSuggestionParser;
    private boolean mFirstFrameDrawn;

    @VisibleForTesting
@@ -115,7 +109,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
        mDashboardFeatureProvider = FeatureFactory.getFactory(context)
                .getDashboardFeatureProvider(context);
        mCache = new IconCache(context);
        mSuggestionParser = parser;

        setHasStableIds(true);

@@ -218,22 +211,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
        }
    }

    // TODO: move this method to SuggestionParser or some other util class
    public void disableSuggestion(Tile suggestion) {
        if (mSuggestionParser == null) {
            return;
        }
        boolean isSmartSuggestionEnabled = FeatureFactory.getFactory(mContext)
                .getSuggestionFeatureProvider(mContext).isSmartSuggestionEnabled(mContext);
        if (mSuggestionParser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
            mContext.getPackageManager().setComponentEnabledSetting(
                    suggestion.intent.getComponent(),
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                    PackageManager.DONT_KILL_APP);
            mSuggestionParser.markCategoryDone(suggestion.category);
        }
    }

    @Override
    public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
@@ -277,13 +254,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
                        ((SettingsActivity) mContext).startSuggestion(suggestion.intent);
                    }
                });
                holder.itemView.findViewById(R.id.overflow).setOnClickListener(
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                showRemoveOption(v, suggestion);
                            }
                        });
                break;
            case R.layout.condition_card:
                final boolean isExpanded = mDashboardData.getItemEntityByPosition(position)
@@ -379,30 +349,24 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
        notifyDashboardDataChanged(prevData);
    }

    private void showRemoveOption(View v, final Tile suggestion) {
        final PopupMenu popup = new PopupMenu(
                new ContextThemeWrapper(mContext, R.style.Theme_AppCompat_DayNight), v);
        popup.getMenu().add(R.string.suggestion_remove).setOnMenuItemClickListener(
                new MenuItem.OnMenuItemClickListener() {
    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        mMetricsFeatureProvider.action(
                                mContext, MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION,
                                DashboardAdapter.getSuggestionIdentifier(mContext, suggestion));
                        disableSuggestion(suggestion);
                        List<Tile> suggestions = mDashboardData.getSuggestions();
    public Tile getSuggestionForPosition(int position) {
        return (Tile) mDashboardData.getItemEntityByPosition(position);
    }

    @Override
    public void onSuggestionDismissed(Tile suggestion) {
        final List<Tile> suggestions = mDashboardData.getSuggestions();
        if (suggestions == null) {
            return;
        }
        suggestions.remove(suggestion);

                        DashboardData prevData = mDashboardData;
        final DashboardData prevData = mDashboardData;
        mDashboardData = new DashboardData.Builder(prevData)
                .setSuggestions(suggestions)
                .build();
        notifyDashboardDataChanged(prevData);

                        return true;
                    }
                });
        popup.show();
    }

    @VisibleForTesting
@@ -513,9 +477,9 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash

        public DashboardItemHolder(View itemView) {
            super(itemView);
            icon = (ImageView) itemView.findViewById(android.R.id.icon);
            title = (TextView) itemView.findViewById(android.R.id.title);
            summary = (TextView) itemView.findViewById(android.R.id.summary);
            icon = itemView.findViewById(android.R.id.icon);
            title = itemView.findViewById(android.R.id.title);
            summary = itemView.findViewById(android.R.id.summary);
        }
    }
}
+24 −13
Original line number Diff line number Diff line
@@ -19,15 +19,17 @@ import android.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v7.util.DiffUtil;
import android.text.TextUtils;

import com.android.settings.R;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settings.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Description about data list used in the DashboardAdapter. In the data list each item can be
@@ -44,7 +46,6 @@ public class DashboardData {

    // id namespace for different type of items.
    private static final int NS_SPACER = 0;
    private static final int NS_SUGGESTION = 1000;
    private static final int NS_ITEMS = 2000;
    private static final int NS_CONDITION = 3000;

@@ -171,6 +172,7 @@ public class DashboardData {
     * {@link #DEFAULT_SUGGESTION_COUNT}.
     *
     * When in expanded mode, display all the suggestions.
     *
     * @return the count of suggestions to display
     */
    public int getDisplayableSuggestionCount() {
@@ -210,6 +212,17 @@ public class DashboardData {
        mId++;
    }

    /**
     * A special count item method for just suggestions. Id is calculated using suggestion hash
     * instead of the position of suggestion in list. This is a more stable id than countItem.
     */
    private void countSuggestion(Tile tile, boolean add) {
        if (add) {
            mItems.add(new Item(tile, R.layout.suggestion_tile, Objects.hash(tile.title), false));
        }
        mId++;
    }

    /**
     * Build the mItems list using mConditions, mSuggestions, mCategories data
     * and mIsShowingAll, mSuggestionMode flag.
@@ -232,8 +245,7 @@ public class DashboardData {
        if (mSuggestions != null) {
            int maxSuggestions = getDisplayableSuggestionCount();
            for (int i = 0; i < mSuggestions.size(); i++) {
                countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions,
                        NS_SUGGESTION);
                countSuggestion(mSuggestions.get(i), i < maxSuggestions);
            }
        }
        resetCount();
@@ -277,7 +289,6 @@ public class DashboardData {
        private List<Condition> mConditions;
        private List<Tile> mSuggestions;


        public Builder() {
        }

+10 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settings.dashboard.conditional.FocusRecyclerView;
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.SuggestionParser;
@@ -70,6 +71,7 @@ public class DashboardSummary extends InstrumentedFragment
    private DashboardFeatureProvider mDashboardFeatureProvider;
    private SuggestionFeatureProvider mSuggestionFeatureProvider;
    private boolean isOnCategoriesChangedCalled;
    private SuggestionDismissController mSuggestionDismissHandler;

    @Override
    public int getMetricsCategory() {
@@ -119,8 +121,7 @@ public class DashboardSummary extends InstrumentedFragment
            }
        }
        if (DEBUG_TIMING) {
            Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime)
                    + " ms");
            Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }

@@ -177,7 +178,7 @@ public class DashboardSummary extends InstrumentedFragment
    @Override
    public void onViewCreated(View view, Bundle bundle) {
        long startTime = System.currentTimeMillis();
        mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
        mDashboard = view.findViewById(R.id.dashboard_container);
        mLayoutManager = new LinearLayoutManager(getContext());
        mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        if (bundle != null) {
@@ -192,6 +193,8 @@ public class DashboardSummary extends InstrumentedFragment
        mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, mMetricsFeatureProvider,
                bundle, mConditionManager.getConditions());
        mDashboard.setAdapter(mAdapter);
        mSuggestionDismissHandler = new SuggestionDismissController(
                getContext(), mDashboard, mSuggestionParser, mAdapter);
        mDashboard.setItemAnimator(new DashboardItemAnimator());
        mSummaryLoader.setSummaryConsumer(mAdapter);
        ConditionAdapterUtils.addDismiss(mDashboard);
@@ -251,7 +254,8 @@ public class DashboardSummary extends InstrumentedFragment
            for (int i = 0; i < suggestions.size(); i++) {
                Tile suggestion = suggestions.get(i);
                if (mSuggestionsChecks.isSuggestionComplete(suggestion)) {
                    mAdapter.disableSuggestion(suggestion);
                    mSuggestionFeatureProvider.dismissSuggestion(
                            context, mSuggestionParser, suggestion);
                    suggestions.remove(i--);
                }
            }
Loading