| /* |
| * Copyright (C) 2016 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. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.printspooler.ui; |
| |
| import android.annotation.IntRange; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.ListActivity; |
| import android.app.LoaderManager; |
| import android.content.ActivityNotFoundException; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.Loader; |
| import android.content.pm.ResolveInfo; |
| import android.database.DataSetObserver; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.print.PrintManager; |
| import android.printservice.recommendation.RecommendationInfo; |
| import android.print.PrintServiceRecommendationsLoader; |
| import android.print.PrintServicesLoader; |
| import android.printservice.PrintServiceInfo; |
| import android.provider.Settings; |
| import android.text.TextUtils; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.Pair; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.Adapter; |
| import android.widget.AdapterView; |
| import android.widget.BaseAdapter; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| import com.android.internal.logging.MetricsLogger; |
| import com.android.internal.logging.nano.MetricsProto.MetricsEvent; |
| import com.android.printspooler.R; |
| |
| import java.text.Collator; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| /** |
| * This is an activity for adding a printer or. It consists of a list fed from three adapters: |
| * <ul> |
| * <li>{@link #mEnabledServicesAdapter} for all enabled services. If a service has an {@link |
| * PrintServiceInfo#getAddPrintersActivityName() add printer activity} this is started |
| * when the item is clicked.</li> |
| * <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page |
| * for this service is opened.</li> |
| * <li>{@link #mRecommendedServicesAdapter} for a link to all services. If this item is clicked |
| * the market app is opened to show all print services.</li> |
| * </ul> |
| */ |
| public class AddPrinterActivity extends ListActivity implements AdapterView.OnItemClickListener { |
| private static final String LOG_TAG = "AddPrinterActivity"; |
| |
| /** Ids for the loaders */ |
| private static final int LOADER_ID_ENABLED_SERVICES = 1; |
| private static final int LOADER_ID_DISABLED_SERVICES = 2; |
| private static final int LOADER_ID_RECOMMENDED_SERVICES = 3; |
| private static final int LOADER_ID_ALL_SERVICES = 4; |
| |
| /** |
| * The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES} |
| * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}. |
| */ |
| private EnabledServicesAdapter mEnabledServicesAdapter; |
| |
| /** |
| * The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES} |
| * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}. |
| */ |
| private DisabledServicesAdapter mDisabledServicesAdapter; |
| |
| /** |
| * The recommended services list. This is filled from the |
| * {@link #LOADER_ID_RECOMMENDED_SERVICES} loader in |
| * {@link PrintServicePrintServiceRecommendationLoaderCallbacks#onLoadFinished}. |
| */ |
| private RecommendedServicesAdapter mRecommendedServicesAdapter; |
| |
| @Override |
| protected void onCreate(@Nullable Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| setContentView(R.layout.add_printer_activity); |
| |
| mEnabledServicesAdapter = new EnabledServicesAdapter(); |
| mDisabledServicesAdapter = new DisabledServicesAdapter(); |
| mRecommendedServicesAdapter = new RecommendedServicesAdapter(); |
| |
| ArrayList<ActionAdapter> adapterList = new ArrayList<>(3); |
| adapterList.add(mEnabledServicesAdapter); |
| adapterList.add(mRecommendedServicesAdapter); |
| adapterList.add(mDisabledServicesAdapter); |
| |
| setListAdapter(new CombinedAdapter(adapterList)); |
| |
| getListView().setOnItemClickListener(this); |
| |
| PrintServiceInfoLoaderCallbacks printServiceLoaderCallbacks = |
| new PrintServiceInfoLoaderCallbacks(); |
| |
| getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks); |
| getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks); |
| getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null, |
| new PrintServicePrintServiceRecommendationLoaderCallbacks()); |
| getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks); |
| } |
| |
| @Override |
| protected void onDestroy() { |
| if (isFinishing()) { |
| MetricsLogger.action(this, MetricsEvent.PRINT_ADD_PRINTERS, |
| mEnabledServicesAdapter.getCount()); |
| } |
| |
| super.onDestroy(); |
| } |
| |
| /** |
| * Callbacks for the loaders operating on list of {@link PrintServiceInfo print service infos}. |
| */ |
| private class PrintServiceInfoLoaderCallbacks implements |
| LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> { |
| @Override |
| public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) { |
| switch (id) { |
| case LOADER_ID_ENABLED_SERVICES: |
| return new PrintServicesLoader( |
| (PrintManager) getSystemService(Context.PRINT_SERVICE), |
| AddPrinterActivity.this, PrintManager.ENABLED_SERVICES); |
| case LOADER_ID_DISABLED_SERVICES: |
| return new PrintServicesLoader( |
| (PrintManager) getSystemService(Context.PRINT_SERVICE), |
| AddPrinterActivity.this, PrintManager.DISABLED_SERVICES); |
| case LOADER_ID_ALL_SERVICES: |
| return new PrintServicesLoader( |
| (PrintManager) getSystemService(Context.PRINT_SERVICE), |
| AddPrinterActivity.this, PrintManager.ALL_SERVICES); |
| default: |
| // not reached |
| return null; |
| } |
| } |
| |
| |
| @Override |
| public void onLoadFinished(Loader<List<PrintServiceInfo>> loader, |
| List<PrintServiceInfo> data) { |
| switch (loader.getId()) { |
| case LOADER_ID_ENABLED_SERVICES: |
| mEnabledServicesAdapter.updateData(data); |
| break; |
| case LOADER_ID_DISABLED_SERVICES: |
| mDisabledServicesAdapter.updateData(data); |
| break; |
| case LOADER_ID_ALL_SERVICES: |
| mRecommendedServicesAdapter.updateInstalledServices(data); |
| default: |
| // not reached |
| } |
| } |
| |
| @Override |
| public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) { |
| if (!isFinishing()) { |
| switch (loader.getId()) { |
| case LOADER_ID_ENABLED_SERVICES: |
| mEnabledServicesAdapter.updateData(null); |
| break; |
| case LOADER_ID_DISABLED_SERVICES: |
| mDisabledServicesAdapter.updateData(null); |
| break; |
| case LOADER_ID_ALL_SERVICES: |
| mRecommendedServicesAdapter.updateInstalledServices(null); |
| break; |
| default: |
| // not reached |
| } |
| } |
| } |
| } |
| |
| /** |
| * Callbacks for the loaders operating on list of {@link RecommendationInfo print service |
| * recommendations}. |
| */ |
| private class PrintServicePrintServiceRecommendationLoaderCallbacks implements |
| LoaderManager.LoaderCallbacks<List<RecommendationInfo>> { |
| @Override |
| public Loader<List<RecommendationInfo>> onCreateLoader(int id, Bundle args) { |
| return new PrintServiceRecommendationsLoader( |
| (PrintManager) getSystemService(Context.PRINT_SERVICE), |
| AddPrinterActivity.this); |
| } |
| |
| |
| @Override |
| public void onLoadFinished(Loader<List<RecommendationInfo>> loader, |
| List<RecommendationInfo> data) { |
| mRecommendedServicesAdapter.updateRecommendations(data); |
| } |
| |
| @Override |
| public void onLoaderReset(Loader<List<RecommendationInfo>> loader) { |
| if (!isFinishing()) { |
| mRecommendedServicesAdapter.updateRecommendations(null); |
| } |
| } |
| } |
| |
| @Override |
| public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
| ((ActionAdapter) getListAdapter()).performAction(position); |
| } |
| |
| /** |
| * Marks an adapter that can can perform an action for a position in it's list. |
| */ |
| private abstract class ActionAdapter extends BaseAdapter { |
| /** |
| * Perform the action for a position in the list. |
| * |
| * @param position The position of the item |
| */ |
| abstract void performAction(@IntRange(from = 0) int position); |
| |
| @Override |
| public boolean areAllItemsEnabled() { |
| return false; |
| } |
| } |
| |
| /** |
| * An adapter presenting multiple sub adapters as a single combined adapter. |
| */ |
| private class CombinedAdapter extends ActionAdapter { |
| /** The adapters to combine */ |
| private final @NonNull ArrayList<ActionAdapter> mAdapters; |
| |
| /** |
| * Create a combined adapter. |
| * |
| * @param adapters the list of adapters to combine |
| */ |
| CombinedAdapter(@NonNull ArrayList<ActionAdapter> adapters) { |
| mAdapters = adapters; |
| |
| final int numAdapters = mAdapters.size(); |
| for (int i = 0; i < numAdapters; i++) { |
| mAdapters.get(i).registerDataSetObserver(new DataSetObserver() { |
| @Override |
| public void onChanged() { |
| notifyDataSetChanged(); |
| } |
| |
| @Override |
| public void onInvalidated() { |
| notifyDataSetChanged(); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public int getCount() { |
| int totalCount = 0; |
| |
| final int numAdapters = mAdapters.size(); |
| for (int i = 0; i < numAdapters; i++) { |
| totalCount += mAdapters.get(i).getCount(); |
| } |
| |
| return totalCount; |
| } |
| |
| /** |
| * Find the sub adapter and the position in the sub-adapter the position in the combined |
| * adapter refers to. |
| * |
| * @param position The position in the combined adapter |
| * |
| * @return The pair of adapter and position in sub adapter |
| */ |
| private @NonNull Pair<ActionAdapter, Integer> getSubAdapter(int position) { |
| final int numAdapters = mAdapters.size(); |
| for (int i = 0; i < numAdapters; i++) { |
| ActionAdapter adapter = mAdapters.get(i); |
| |
| if (position < adapter.getCount()) { |
| return new Pair<>(adapter, position); |
| } else { |
| position -= adapter.getCount(); |
| } |
| } |
| |
| throw new IllegalArgumentException("Invalid position"); |
| } |
| |
| @Override |
| public int getItemViewType(int position) { |
| int numLowerViewTypes = 0; |
| |
| final int numAdapters = mAdapters.size(); |
| for (int i = 0; i < numAdapters; i++) { |
| Adapter adapter = mAdapters.get(i); |
| |
| if (position < adapter.getCount()) { |
| return numLowerViewTypes + adapter.getItemViewType(position); |
| } else { |
| numLowerViewTypes += adapter.getViewTypeCount(); |
| position -= adapter.getCount(); |
| } |
| } |
| |
| throw new IllegalArgumentException("Invalid position"); |
| } |
| |
| @Override |
| public int getViewTypeCount() { |
| int totalViewCount = 0; |
| |
| final int numAdapters = mAdapters.size(); |
| for (int i = 0; i < numAdapters; i++) { |
| totalViewCount += mAdapters.get(i).getViewTypeCount(); |
| } |
| |
| return totalViewCount; |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position); |
| |
| return realPosition.first.getView(realPosition.second, convertView, parent); |
| } |
| |
| @Override |
| public Object getItem(int position) { |
| Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position); |
| |
| return realPosition.first.getItem(realPosition.second); |
| } |
| |
| @Override |
| public long getItemId(int position) { |
| return position; |
| } |
| |
| @Override |
| public boolean isEnabled(int position) { |
| Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position); |
| |
| return realPosition.first.isEnabled(realPosition.second); |
| } |
| |
| @Override |
| public void performAction(@IntRange(from = 0) int position) { |
| Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position); |
| |
| realPosition.first.performAction(realPosition.second); |
| } |
| } |
| |
| /** |
| * Superclass for all adapters that just display a list of {@link PrintServiceInfo}. |
| */ |
| private abstract class PrintServiceInfoAdapter extends ActionAdapter { |
| /** |
| * Raw data of the list. |
| * |
| * @see #updateData(List) |
| */ |
| private @NonNull List<PrintServiceInfo> mServices; |
| |
| /** |
| * Create a new adapter. |
| */ |
| PrintServiceInfoAdapter() { |
| mServices = Collections.emptyList(); |
| } |
| |
| /** |
| * Update the data. |
| * |
| * @param services The new raw data. |
| */ |
| void updateData(@Nullable List<PrintServiceInfo> services) { |
| if (services == null || services.isEmpty()) { |
| mServices = Collections.emptyList(); |
| } else { |
| mServices = services; |
| } |
| |
| notifyDataSetChanged(); |
| } |
| |
| @Override |
| public int getViewTypeCount() { |
| return 2; |
| } |
| |
| @Override |
| public int getItemViewType(int position) { |
| if (position == 0) { |
| return 0; |
| } else { |
| return 1; |
| } |
| } |
| |
| @Override |
| public int getCount() { |
| if (mServices.isEmpty()) { |
| return 0; |
| } else { |
| return mServices.size() + 1; |
| } |
| } |
| |
| @Override |
| public Object getItem(int position) { |
| if (position == 0) { |
| return null; |
| } else { |
| return mServices.get(position - 1); |
| } |
| } |
| |
| @Override |
| public boolean isEnabled(int position) { |
| return position != 0; |
| } |
| |
| @Override |
| public long getItemId(int position) { |
| return position; |
| } |
| } |
| |
| /** |
| * Adapter for the enabled services. |
| */ |
| private class EnabledServicesAdapter extends PrintServiceInfoAdapter { |
| @Override |
| public void performAction(@IntRange(from = 0) int position) { |
| Intent intent = getAddPrinterIntent((PrintServiceInfo) getItem(position)); |
| if (intent != null) { |
| try { |
| startActivity(intent); |
| } catch (ActivityNotFoundException|SecurityException e) { |
| Log.e(LOG_TAG, "Cannot start add printers activity", e); |
| } |
| } |
| } |
| |
| /** |
| * Get the intent used to launch the add printers activity. |
| * |
| * @param service The service the printer should be added for |
| * |
| * @return The intent to launch the activity or null if the activity could not be launched. |
| */ |
| private Intent getAddPrinterIntent(@NonNull PrintServiceInfo service) { |
| String addPrinterActivityName = service.getAddPrintersActivityName(); |
| |
| if (!TextUtils.isEmpty(addPrinterActivityName)) { |
| Intent intent = new Intent(Intent.ACTION_MAIN); |
| intent.setComponent(new ComponentName(service.getComponentName().getPackageName(), |
| addPrinterActivityName)); |
| |
| List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities( |
| intent, 0); |
| if (!resolvedActivities.isEmpty()) { |
| // The activity is a component name, therefore it is one or none. |
| if (resolvedActivities.get(0).activityInfo.exported) { |
| return intent; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| if (position == 0) { |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header, |
| parent, false); |
| } |
| |
| ((TextView) convertView.findViewById(R.id.text)) |
| .setText(R.string.enabled_services_title); |
| |
| return convertView; |
| } |
| |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate(R.layout.enabled_print_services_list_item, |
| parent, false); |
| } |
| |
| PrintServiceInfo service = (PrintServiceInfo) getItem(position); |
| |
| TextView title = (TextView) convertView.findViewById(R.id.title); |
| ImageView icon = (ImageView) convertView.findViewById(R.id.icon); |
| TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle); |
| |
| title.setText(service.getResolveInfo().loadLabel(getPackageManager())); |
| icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager())); |
| |
| if (getAddPrinterIntent(service) == null) { |
| subtitle.setText(getString(R.string.cannot_add_printer)); |
| } else { |
| subtitle.setText(getString(R.string.select_to_add_printers)); |
| } |
| |
| return convertView; |
| } |
| } |
| |
| /** |
| * Adapter for the disabled services. |
| */ |
| private class DisabledServicesAdapter extends PrintServiceInfoAdapter { |
| @Override |
| public void performAction(@IntRange(from = 0) int position) { |
| ((PrintManager) getSystemService(Context.PRINT_SERVICE)).setPrintServiceEnabled( |
| ((PrintServiceInfo) getItem(position)).getComponentName(), true); |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| if (position == 0) { |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header, |
| parent, false); |
| } |
| |
| ((TextView) convertView.findViewById(R.id.text)) |
| .setText(R.string.disabled_services_title); |
| |
| return convertView; |
| } |
| |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate( |
| R.layout.disabled_print_services_list_item, parent, false); |
| } |
| |
| PrintServiceInfo service = (PrintServiceInfo) getItem(position); |
| |
| TextView title = (TextView) convertView.findViewById(R.id.title); |
| ImageView icon = (ImageView) convertView.findViewById(R.id.icon); |
| |
| title.setText(service.getResolveInfo().loadLabel(getPackageManager())); |
| icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager())); |
| |
| return convertView; |
| } |
| } |
| |
| /** |
| * Adapter for the recommended services. |
| */ |
| private class RecommendedServicesAdapter extends ActionAdapter { |
| /** Package names of all installed print services */ |
| private @NonNull final ArraySet<String> mInstalledServices; |
| |
| /** All print service recommendations */ |
| private @Nullable List<RecommendationInfo> mRecommendations; |
| |
| /** |
| * Sorted print service recommendations for services that are not installed |
| * |
| * @see #filterRecommendations |
| */ |
| private @Nullable List<RecommendationInfo> mFilteredRecommendations; |
| |
| /** |
| * Create a new adapter. |
| */ |
| private RecommendedServicesAdapter() { |
| mInstalledServices = new ArraySet<>(); |
| } |
| |
| @Override |
| public int getCount() { |
| if (mFilteredRecommendations == null) { |
| return 2; |
| } else { |
| return mFilteredRecommendations.size() + 2; |
| } |
| } |
| |
| @Override |
| public int getViewTypeCount() { |
| return 3; |
| } |
| |
| /** |
| * @return The position the all services link is at. |
| */ |
| private int getAllServicesPos() { |
| return getCount() - 1; |
| } |
| |
| @Override |
| public int getItemViewType(int position) { |
| if (position == 0) { |
| return 0; |
| } else if (getAllServicesPos() == position) { |
| return 1; |
| } else { |
| return 2; |
| } |
| } |
| |
| @Override |
| public Object getItem(int position) { |
| if (position == 0 || position == getAllServicesPos()) { |
| return null; |
| } else { |
| return mFilteredRecommendations.get(position - 1); |
| } |
| } |
| |
| @Override |
| public long getItemId(int position) { |
| return position; |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| if (position == 0) { |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header, |
| parent, false); |
| } |
| |
| ((TextView) convertView.findViewById(R.id.text)) |
| .setText(R.string.recommended_services_title); |
| |
| return convertView; |
| } else if (position == getAllServicesPos()) { |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item, |
| parent, false); |
| } |
| } else { |
| RecommendationInfo recommendation = (RecommendationInfo) getItem(position); |
| |
| if (convertView == null) { |
| convertView = getLayoutInflater().inflate( |
| R.layout.print_service_recommendations_list_item, parent, false); |
| } |
| |
| ((TextView) convertView.findViewById(R.id.title)).setText(recommendation.getName()); |
| |
| ((TextView) convertView.findViewById(R.id.subtitle)).setText(getResources() |
| .getQuantityString(R.plurals.print_services_recommendation_subtitle, |
| recommendation.getNumDiscoveredPrinters(), |
| recommendation.getNumDiscoveredPrinters())); |
| |
| return convertView; |
| } |
| |
| return convertView; |
| } |
| |
| @Override |
| public boolean isEnabled(int position) { |
| return position != 0; |
| } |
| |
| @Override |
| public void performAction(@IntRange(from = 0) int position) { |
| if (position == getAllServicesPos()) { |
| String searchUri = Settings.Secure |
| .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI); |
| |
| if (searchUri != null) { |
| try { |
| startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri))); |
| } catch (ActivityNotFoundException e) { |
| Log.e(LOG_TAG, "Cannot start market", e); |
| } |
| } |
| } else { |
| RecommendationInfo recommendation = (RecommendationInfo) getItem(position); |
| |
| MetricsLogger.action(AddPrinterActivity.this, |
| MetricsEvent.ACTION_PRINT_RECOMMENDED_SERVICE_INSTALL, |
| recommendation.getPackageName().toString()); |
| |
| try { |
| startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString( |
| R.string.uri_package_details, recommendation.getPackageName())))); |
| } catch (ActivityNotFoundException e) { |
| Log.e(LOG_TAG, "Cannot start market", e); |
| } |
| } |
| } |
| |
| /** |
| * Filter recommended services. |
| */ |
| private void filterRecommendations() { |
| if (mRecommendations == null) { |
| mFilteredRecommendations = null; |
| } else { |
| mFilteredRecommendations = new ArrayList<>(); |
| |
| // Filter out recommendations for already installed services |
| final int numRecommendations = mRecommendations.size(); |
| for (int i = 0; i < numRecommendations; i++) { |
| RecommendationInfo recommendation = mRecommendations.get(i); |
| |
| if (!mInstalledServices.contains(recommendation.getPackageName())) { |
| mFilteredRecommendations.add(recommendation); |
| } |
| } |
| } |
| |
| notifyDataSetChanged(); |
| } |
| |
| /** |
| * Update the installed print services. |
| * |
| * @param services The new set of services |
| */ |
| public void updateInstalledServices(List<PrintServiceInfo> services) { |
| mInstalledServices.clear(); |
| |
| if (services != null) { |
| final int numServices = services.size(); |
| for (int i = 0; i < numServices; i++) { |
| mInstalledServices.add(services.get(i).getComponentName().getPackageName()); |
| } |
| } |
| |
| filterRecommendations(); |
| } |
| |
| /** |
| * Update the recommended print services. |
| * |
| * @param recommendations The new set of recommendations |
| */ |
| public void updateRecommendations(List<RecommendationInfo> recommendations) { |
| if (recommendations != null) { |
| final Collator collator = Collator.getInstance(); |
| |
| // Sort recommendations (early conditions are more important) |
| // - higher number of discovered printers first |
| // - single vendor services first |
| // - alphabetically |
| Collections.sort(recommendations, |
| new Comparator<RecommendationInfo>() { |
| @Override public int compare(RecommendationInfo o1, |
| RecommendationInfo o2) { |
| if (o1.getNumDiscoveredPrinters() != |
| o2.getNumDiscoveredPrinters()) { |
| return o2.getNumDiscoveredPrinters() - |
| o1.getNumDiscoveredPrinters(); |
| } else if (o1.recommendsMultiVendorService() |
| != o2.recommendsMultiVendorService()) { |
| if (o1.recommendsMultiVendorService()) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } else { |
| return collator.compare(o1.getName().toString(), |
| o2.getName().toString()); |
| } |
| } |
| }); |
| } |
| |
| mRecommendations = recommendations; |
| |
| filterRecommendations(); |
| } |
| } |
| } |