Home | History | Annotate | Download | only in suggestions
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 package com.android.car.settings.suggestions;
     17 
     18 import android.annotation.NonNull;
     19 import android.annotation.Nullable;
     20 import android.app.PendingIntent;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.graphics.drawable.Drawable;
     24 import android.os.Bundle;
     25 import android.service.settings.suggestions.Suggestion;
     26 import android.support.annotation.StringRes;
     27 import android.support.v4.app.LoaderManager;
     28 import android.support.v4.content.Loader;
     29 
     30 import com.android.car.list.TypedPagedListAdapter;
     31 import com.android.car.settings.R;
     32 import com.android.car.settings.common.Logger;
     33 import com.android.settingslib.suggestions.SuggestionController;
     34 import com.android.settingslib.suggestions.SuggestionControllerMixin;
     35 import com.android.settingslib.suggestions.SuggestionLoader;
     36 import com.android.settingslib.utils.IconCache;
     37 
     38 import java.util.ArrayList;
     39 import java.util.List;
     40 
     41 
     42 /**
     43  * Retrieves suggestions and prepares them for rendering.
     44  * Modeled after {@link SuggestionControllerMixin}, differs by implementing support library version
     45  * of LoaderManager and Loader. Does not implement use of LifeCycle.
     46  */
     47 public class SettingsSuggestionsController implements
     48         SuggestionController.ServiceConnectionListener,
     49         LoaderManager.LoaderCallbacks<List<Suggestion>> {
     50     private static final Logger LOG = new Logger(SettingsSuggestionsController.class);
     51     private static final ComponentName mComponentName = new ComponentName(
     52             "com.android.settings.intelligence",
     53             "com.android.settings.intelligence.suggestions.SuggestionService");
     54     // These values are hard coded until we receive the OK to plumb them through
     55     // SettingsIntelligence. This is ok as right now only SUW uses this framework.
     56     @StringRes
     57     private static final int PRIMARY_ACTION_ID = R.string.suggestion_primary_button;
     58     @StringRes
     59     private static final int SECONDARY_ACTION_ID = R.string.suggestion_secondary_button;
     60 
     61     private final Context mContext;
     62     private final LoaderManager mLoaderManager;
     63     private final Listener mListener;
     64     private final SuggestionController mSuggestionController;
     65     private final IconCache mIconCache;
     66 
     67     public SettingsSuggestionsController(
     68             Context context,
     69             LoaderManager loaderManager,
     70             @NonNull Listener listener) {
     71         mContext = context;
     72         mLoaderManager = loaderManager;
     73         mListener = listener;
     74         mIconCache = new IconCache(context);
     75         mSuggestionController = new SuggestionController(
     76                 mContext,
     77                 mComponentName,
     78                 /* listener= */ this);
     79     }
     80 
     81     @Override
     82     public void onServiceConnected() {
     83         LOG.v("onServiceConnected");
     84         mLoaderManager.restartLoader(
     85                 SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS,
     86                 /* args= */ null,
     87                 /* callback= */ this);
     88     }
     89 
     90     @Override
     91     public void onServiceDisconnected() {
     92         LOG.v("onServiceDisconnected");
     93         cleanupLoader();
     94     }
     95 
     96     @NonNull
     97     @Override
     98     public Loader<List<Suggestion>> onCreateLoader(int id, @Nullable Bundle args) {
     99         LOG.v("onCreateLoader: " + id);
    100         if (id == SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS) {
    101             return new SettingsSuggestionsLoader(mContext, mSuggestionController);
    102         }
    103         throw new IllegalArgumentException("This loader id is not supported " + id);
    104     }
    105 
    106     @Override
    107     public void onLoadFinished(
    108             @NonNull Loader<List<Suggestion>> loader,
    109             List<Suggestion> suggestionList) {
    110         LOG.v("onLoadFinished");
    111         if (suggestionList == null) {
    112             return;
    113         }
    114         ArrayList<TypedPagedListAdapter.LineItem> items = new ArrayList<>();
    115         for (final Suggestion suggestion : suggestionList) {
    116             LOG.v("Suggestion ID: " + suggestion.getId());
    117             Drawable itemIcon = mIconCache.getIcon(suggestion.getIcon());
    118             SuggestionLineItem suggestionLineItem =
    119                     new SuggestionLineItem(
    120                             suggestion.getTitle(),
    121                             suggestion.getSummary(),
    122                             itemIcon,
    123                             mContext.getString(PRIMARY_ACTION_ID),
    124                             mContext.getString(SECONDARY_ACTION_ID),
    125                             v -> {
    126                                 try {
    127                                     suggestion.getPendingIntent().send();
    128                                     launchSuggestion(suggestion);
    129                                 } catch (PendingIntent.CanceledException e) {
    130                                     LOG.w("Failed to start suggestion " + suggestion.getTitle());
    131                                 }
    132                             },
    133                             adapterPosition -> {
    134                                 dismissSuggestion(suggestion);
    135                                 mListener.onSuggestionDismissed(adapterPosition);
    136 
    137                             });
    138             items.add(suggestionLineItem);
    139         }
    140         mListener.onSuggestionsLoaded(items);
    141     }
    142 
    143     @Override
    144     public void onLoaderReset(@NonNull Loader<List<Suggestion>> loader) {
    145         LOG.v("onLoaderReset");
    146     }
    147 
    148     /**
    149      * Start the suggestions controller.
    150      */
    151     public void start() {
    152         LOG.v("Start");
    153         mSuggestionController.start();
    154     }
    155 
    156     /**
    157      * Stop the suggestions controller.
    158      */
    159     public void stop() {
    160         LOG.v("Stop");
    161         mSuggestionController.stop();
    162         cleanupLoader();
    163 
    164     }
    165 
    166     private void cleanupLoader() {
    167         LOG.v("cleanupLoader");
    168         mLoaderManager.destroyLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS);
    169     }
    170 
    171     private void dismissSuggestion(Suggestion suggestion) {
    172         LOG.v("dismissSuggestion");
    173         mSuggestionController.dismissSuggestions(suggestion);
    174     }
    175 
    176     private void launchSuggestion(Suggestion suggestion) {
    177         LOG.v("launchSuggestion");
    178         mSuggestionController.launchSuggestion(suggestion);
    179     }
    180 
    181     /**
    182      * Listener interface to notify of data state changes and actions.
    183      */
    184     public interface Listener {
    185         /**
    186          * Invoked when deferred setup items have been loaded.
    187          *
    188          * @param suggestions List of deferred setup suggestions.
    189          */
    190         void onSuggestionsLoaded(@NonNull ArrayList<TypedPagedListAdapter.LineItem> suggestions);
    191 
    192         /***
    193          * Invoked when a suggestion is dismissed.
    194          *
    195          * @param adapterPosition the position of the suggestion item in it's adapter.
    196          */
    197         void onSuggestionDismissed(int adapterPosition);
    198     }
    199 }
    200