Home | History | Annotate | Download | only in specialaccess
      1 /*
      2  * Copyright (C) 2017 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 
     17 package com.android.tv.settings.device.apps.specialaccess;
     18 
     19 import android.app.Application;
     20 import android.arch.lifecycle.Lifecycle;
     21 import android.arch.lifecycle.LifecycleObserver;
     22 import android.content.Context;
     23 import android.support.annotation.NonNull;
     24 import android.support.v7.preference.Preference;
     25 import android.support.v7.preference.PreferenceGroup;
     26 
     27 import com.android.settingslib.applications.ApplicationsState;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Comparator;
     31 import java.util.List;
     32 
     33 /**
     34  * A class to manage a list of apps in a {@link PreferenceGroup}. The list is configured by passing
     35  * an {@link ApplicationsState.AppFilter} and a {@link Comparator} for
     36  * {@link ApplicationsState.AppEntry} objects, and the PreferenceGroup is manipulated through the
     37  * {@link Callback} object.
     38  */
     39 public class ManageApplicationsController implements LifecycleObserver {
     40     /**
     41      *  Use this preference key for a header pref not removed during refresh
     42      */
     43     public static final String HEADER_KEY = "header";
     44 
     45     private final Callback mCallback;
     46     private final Lifecycle mLifecycle;
     47     private final ApplicationsState.AppFilter mFilter;
     48     private final Comparator<ApplicationsState.AppEntry> mComparator;
     49 
     50     private ApplicationsState.Session mAppSession;
     51     private ApplicationsState mApplicationsState;
     52     private final ApplicationsState.Callbacks mAppSessionCallbacks =
     53             new ApplicationsState.Callbacks() {
     54 
     55                 @Override
     56                 public void onRunningStateChanged(boolean running) {
     57                     updateAppList();
     58                 }
     59 
     60                 @Override
     61                 public void onPackageListChanged() {
     62                     updateAppList();
     63                 }
     64 
     65                 @Override
     66                 public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
     67                     updateAppList(apps);
     68                 }
     69 
     70                 @Override
     71                 public void onPackageIconChanged() {
     72                     updateAppList();
     73                 }
     74 
     75                 @Override
     76                 public void onPackageSizeChanged(String packageName) {
     77                     updateAppList();
     78                 }
     79 
     80                 @Override
     81                 public void onAllSizesComputed() {
     82                     updateAppList();
     83                 }
     84 
     85                 @Override
     86                 public void onLauncherInfoChanged() {
     87                     updateAppList();
     88                 }
     89 
     90                 @Override
     91                 public void onLoadEntriesCompleted() {
     92                     updateAppList();
     93                 }
     94             };
     95 
     96     public ManageApplicationsController(@NonNull Context context, @NonNull Callback callback,
     97             @NonNull Lifecycle lifecycle, ApplicationsState.AppFilter filter,
     98             Comparator<ApplicationsState.AppEntry> comparator) {
     99         mCallback = callback;
    100         lifecycle.addObserver(this);
    101         mLifecycle = lifecycle;
    102         mFilter = filter;
    103         mComparator = comparator;
    104         mApplicationsState = ApplicationsState.getInstance(
    105                 (Application) context.getApplicationContext());
    106         mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, mLifecycle);
    107         updateAppList();
    108     }
    109 
    110     /**
    111      * Call this method to trigger the app list to refresh.
    112      */
    113     public void updateAppList() {
    114         ApplicationsState.AppFilter filter = new ApplicationsState.CompoundFilter(
    115                 mFilter, ApplicationsState.FILTER_NOT_HIDE);
    116         ArrayList<ApplicationsState.AppEntry> apps = mAppSession.rebuild(filter, mComparator);
    117         if (apps != null) {
    118             updateAppList(apps);
    119         }
    120     }
    121 
    122     private void updateAppList(ArrayList<ApplicationsState.AppEntry> apps) {
    123         PreferenceGroup group = mCallback.getAppPreferenceGroup();
    124         final List<Preference> newList = new ArrayList<>(apps.size() + 1);
    125         for (final ApplicationsState.AppEntry entry : apps) {
    126             final String packageName = entry.info.packageName;
    127             mApplicationsState.ensureIcon(entry);
    128             Preference recycle = group.findPreference(packageName);
    129             if (recycle == null) {
    130                 recycle = mCallback.createAppPreference();
    131             }
    132             newList.add(mCallback.bindPreference(recycle, entry));
    133         }
    134         final Preference header = group.findPreference(HEADER_KEY);
    135         // Because we're sorting the app entries, we should remove-all to ensure that sort order
    136         // is retained
    137         group.removeAll();
    138         if (header != null) {
    139             group.addPreference(header);
    140         }
    141         if (newList.size() > 0) {
    142             for (Preference prefToAdd : newList) {
    143                 group.addPreference(prefToAdd);
    144             }
    145         } else {
    146             group.addPreference(mCallback.getEmptyPreference());
    147         }
    148     }
    149 
    150     /**
    151      * Callback interface for this class to manipulate the list of app preferences.
    152      */
    153     public interface Callback {
    154         /**
    155          * Configure the {@link Preference} object with the data in the
    156          * {@link ApplicationsState.AppEntry}
    157          * @param preference Preference to configure
    158          * @param entry Entry containing data to bind
    159          * @return Return the configured Preference object
    160          */
    161         @NonNull Preference bindPreference(@NonNull Preference preference,
    162                 ApplicationsState.AppEntry entry);
    163 
    164         /**
    165          * Create a new instance of a {@link Preference} subclass to be used to display an
    166          * {@link ApplicationsState.AppEntry}
    167          * @return New Preference object
    168          */
    169         @NonNull Preference createAppPreference();
    170 
    171         /**
    172          * @return {@link Preference} object to be used as an empty state placeholder
    173          */
    174         @NonNull Preference getEmptyPreference();
    175 
    176         /**
    177          * The {@link PreferenceGroup} returned here should contain only app preference objects,
    178          * plus optionally a header preference with the key {@link #HEADER_KEY}
    179          * @return PreferenceGroup to manipulate
    180          */
    181         @NonNull PreferenceGroup getAppPreferenceGroup();
    182     }
    183 }
    184