Home | History | Annotate | Download | only in print
      1 /*
      2  * Copyright (C) 2013 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.settings.print;
     18 
     19 import android.app.Activity;
     20 import android.app.LoaderManager;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentSender.SendIntentException;
     25 import android.content.Loader;
     26 import android.content.pm.ResolveInfo;
     27 import android.database.DataSetObserver;
     28 import android.graphics.Color;
     29 import android.graphics.drawable.ColorDrawable;
     30 import android.graphics.drawable.Drawable;
     31 import android.os.Bundle;
     32 import android.print.PrintManager;
     33 import android.print.PrintServicesLoader;
     34 import android.print.PrinterDiscoverySession;
     35 import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
     36 import android.print.PrinterId;
     37 import android.print.PrinterInfo;
     38 import android.printservice.PrintServiceInfo;
     39 import android.text.TextUtils;
     40 import android.util.Log;
     41 import android.util.TypedValue;
     42 import android.view.LayoutInflater;
     43 import android.view.Menu;
     44 import android.view.MenuInflater;
     45 import android.view.MenuItem;
     46 import android.view.View;
     47 import android.view.ViewGroup;
     48 import android.view.View.OnClickListener;
     49 import android.view.accessibility.AccessibilityManager;
     50 import android.widget.AdapterView;
     51 import android.widget.BaseAdapter;
     52 import android.widget.Filter;
     53 import android.widget.Filterable;
     54 import android.widget.ImageView;
     55 import android.widget.LinearLayout;
     56 import android.widget.ListView;
     57 import android.widget.SearchView;
     58 import android.widget.Switch;
     59 import android.widget.TextView;
     60 
     61 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     62 import com.android.settings.R;
     63 import com.android.settings.SettingsActivity;
     64 import com.android.settings.SettingsPreferenceFragment;
     65 import com.android.settings.widget.SwitchBar;
     66 import com.android.settings.widget.ToggleSwitch;
     67 
     68 import java.util.ArrayList;
     69 import java.util.LinkedHashMap;
     70 import java.util.List;
     71 import java.util.Map;
     72 
     73 /**
     74  * Fragment with print service settings.
     75  */
     76 public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
     77         implements SwitchBar.OnSwitchChangeListener,
     78         LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
     79 
     80     private static final String LOG_TAG = "PrintServiceSettingsFragment";
     81 
     82     private static final int LOADER_ID_PRINTERS_LOADER = 1;
     83     private static final int LOADER_ID_PRINT_SERVICE_LOADER = 2;
     84 
     85     private final DataSetObserver mDataObserver = new DataSetObserver() {
     86         @Override
     87         public void onChanged() {
     88             invalidateOptionsMenuIfNeeded();
     89             updateEmptyView();
     90         }
     91 
     92         @Override
     93         public void onInvalidated() {
     94             invalidateOptionsMenuIfNeeded();
     95         }
     96 
     97         private void invalidateOptionsMenuIfNeeded() {
     98             final int unfilteredItemCount = mPrintersAdapter.getUnfilteredCount();
     99             if ((mLastUnfilteredItemCount <= 0 && unfilteredItemCount > 0)
    100                     || mLastUnfilteredItemCount > 0 && unfilteredItemCount <= 0) {
    101                 getActivity().invalidateOptionsMenu();
    102             }
    103             mLastUnfilteredItemCount = unfilteredItemCount;
    104         }
    105     };
    106 
    107     private SwitchBar mSwitchBar;
    108     private ToggleSwitch mToggleSwitch;
    109 
    110     private String mPreferenceKey;
    111 
    112     private Intent mSettingsIntent;
    113 
    114     private Intent mAddPrintersIntent;
    115 
    116     private ComponentName mComponentName;
    117 
    118     private PrintersAdapter mPrintersAdapter;
    119 
    120     private int mLastUnfilteredItemCount;
    121 
    122     private boolean mServiceEnabled;
    123 
    124     private SearchView mSearchView;
    125 
    126     @Override
    127     public int getMetricsCategory() {
    128         return MetricsEvent.PRINT_SERVICE_SETTINGS;
    129     }
    130 
    131     @Override
    132     public void onCreate(Bundle icicle) {
    133         super.onCreate(icicle);
    134 
    135         String title = getArguments().getString(PrintSettingsFragment.EXTRA_TITLE);
    136         if (!TextUtils.isEmpty(title)) {
    137             getActivity().setTitle(title);
    138         }
    139     }
    140 
    141     @Override
    142     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    143             Bundle savedInstanceState) {
    144         View root = super.onCreateView(inflater, container, savedInstanceState);
    145 
    146         mServiceEnabled = getArguments().getBoolean(PrintSettingsFragment.EXTRA_CHECKED);
    147 
    148         return root;
    149     }
    150 
    151     @Override
    152     public void onStart() {
    153         super.onStart();
    154         updateEmptyView();
    155         updateUiForServiceState();
    156     }
    157 
    158     @Override
    159     public void onPause() {
    160         if (mSearchView != null) {
    161             mSearchView.setOnQueryTextListener(null);
    162         }
    163         super.onPause();
    164     }
    165 
    166     @Override
    167     public void onStop() {
    168         super.onStop();
    169     }
    170 
    171     @Override
    172     public void onViewCreated(View view, Bundle savedInstanceState) {
    173         super.onViewCreated(view, savedInstanceState);
    174         initComponents();
    175         updateUiForArguments();
    176         getListView().setVisibility(View.GONE);
    177         getBackupListView().setVisibility(View.VISIBLE);
    178     }
    179 
    180     @Override
    181     public void onDestroyView() {
    182         super.onDestroyView();
    183         mSwitchBar.removeOnSwitchChangeListener(this);
    184         mSwitchBar.hide();
    185     }
    186 
    187     private void onPreferenceToggled(String preferenceKey, boolean enabled) {
    188         ((PrintManager)getContext().getSystemService(Context.PRINT_SERVICE))
    189                 .setPrintServiceEnabled(mComponentName, enabled);
    190     }
    191 
    192     private ListView getBackupListView() {
    193         return (ListView) getView().findViewById(R.id.backup_list);
    194     }
    195 
    196     private void updateEmptyView() {
    197         ViewGroup contentRoot = (ViewGroup) getListView().getParent();
    198         View emptyView = getBackupListView().getEmptyView();
    199         if (!mToggleSwitch.isChecked()) {
    200             if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
    201                 contentRoot.removeView(emptyView);
    202                 emptyView = null;
    203             }
    204             if (emptyView == null) {
    205                 emptyView = getActivity().getLayoutInflater().inflate(
    206                         R.layout.empty_print_state, contentRoot, false);
    207                 ImageView iconView = (ImageView) emptyView.findViewById(R.id.icon);
    208                 iconView.setContentDescription(getString(R.string.print_service_disabled));
    209                 TextView textView = (TextView) emptyView.findViewById(R.id.message);
    210                 textView.setText(R.string.print_service_disabled);
    211                 contentRoot.addView(emptyView);
    212                 getBackupListView().setEmptyView(emptyView);
    213             }
    214         } else if (mPrintersAdapter.getUnfilteredCount() <= 0) {
    215             if (emptyView != null
    216                     && emptyView.getId() != R.id.empty_printers_list_service_enabled) {
    217                 contentRoot.removeView(emptyView);
    218                 emptyView = null;
    219             }
    220             if (emptyView == null) {
    221                 emptyView = getActivity().getLayoutInflater().inflate(
    222                         R.layout.empty_printers_list_service_enabled, contentRoot, false);
    223                 contentRoot.addView(emptyView);
    224                 getBackupListView().setEmptyView(emptyView);
    225             }
    226         } else if (mPrintersAdapter.getCount() <= 0) {
    227             if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
    228                 contentRoot.removeView(emptyView);
    229                 emptyView = null;
    230             }
    231             if (emptyView == null) {
    232                 emptyView = getActivity().getLayoutInflater().inflate(
    233                         R.layout.empty_print_state, contentRoot, false);
    234                 ImageView iconView = (ImageView) emptyView.findViewById(R.id.icon);
    235                 iconView.setContentDescription(getString(R.string.print_no_printers_found));
    236                 TextView textView = (TextView) emptyView.findViewById(R.id.message);
    237                 textView.setText(R.string.print_no_printers_found);
    238                 contentRoot.addView(emptyView);
    239                 getBackupListView().setEmptyView(emptyView);
    240             }
    241         }
    242     }
    243 
    244     private void updateUiForServiceState() {
    245         if (mServiceEnabled) {
    246             mSwitchBar.setCheckedInternal(true);
    247             mPrintersAdapter.enable();
    248         } else {
    249             mSwitchBar.setCheckedInternal(false);
    250             mPrintersAdapter.disable();
    251         }
    252         getActivity().invalidateOptionsMenu();
    253     }
    254 
    255     private void initComponents() {
    256         mPrintersAdapter = new PrintersAdapter();
    257         mPrintersAdapter.registerDataSetObserver(mDataObserver);
    258 
    259         final SettingsActivity activity = (SettingsActivity) getActivity();
    260 
    261         mSwitchBar = activity.getSwitchBar();
    262         mSwitchBar.addOnSwitchChangeListener(this);
    263         mSwitchBar.show();
    264 
    265         mToggleSwitch = mSwitchBar.getSwitch();
    266         mToggleSwitch.setOnBeforeCheckedChangeListener(new ToggleSwitch.OnBeforeCheckedChangeListener() {
    267             @Override
    268             public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
    269                 onPreferenceToggled(mPreferenceKey, checked);
    270                 return false;
    271             }
    272         });
    273 
    274         getBackupListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
    275         getBackupListView().setAdapter(mPrintersAdapter);
    276         getBackupListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
    277             @Override
    278             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    279                 PrinterInfo printer = (PrinterInfo) mPrintersAdapter.getItem(position);
    280 
    281                 if (printer.getInfoIntent() != null) {
    282                     try {
    283                         getActivity().startIntentSender(printer.getInfoIntent().getIntentSender(),
    284                                 null, 0, 0, 0);
    285                     } catch (SendIntentException e) {
    286                         Log.e(LOG_TAG, "Could not execute info intent: %s", e);
    287                     }
    288                 }
    289             }
    290         });
    291     }
    292 
    293 
    294     @Override
    295     public void onSwitchChanged(Switch switchView, boolean isChecked) {
    296         updateEmptyView();
    297     }
    298 
    299     private void updateUiForArguments() {
    300         Bundle arguments = getArguments();
    301 
    302         // Component name.
    303         mComponentName = ComponentName.unflattenFromString(arguments
    304                 .getString(PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME));
    305 
    306         // Key.
    307         mPreferenceKey = mComponentName.flattenToString();
    308 
    309         // Enabled.
    310         final boolean enabled = arguments.getBoolean(PrintSettingsFragment.EXTRA_CHECKED);
    311         mSwitchBar.setCheckedInternal(enabled);
    312 
    313         getLoaderManager().initLoader(LOADER_ID_PRINT_SERVICE_LOADER, null, this);
    314         setHasOptionsMenu(true);
    315     }
    316 
    317     @Override
    318     public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
    319         return new PrintServicesLoader(
    320                 (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE), getContext(),
    321                 PrintManager.ALL_SERVICES);
    322     }
    323 
    324     @Override
    325     public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
    326             List<PrintServiceInfo> services) {
    327         PrintServiceInfo service = null;
    328 
    329         if (services != null) {
    330             final int numServices = services.size();
    331             for (int i = 0; i < numServices; i++) {
    332                 if (services.get(i).getComponentName().equals(mComponentName)) {
    333                     service = services.get(i);
    334                     break;
    335                 }
    336             }
    337         }
    338 
    339         if (service == null) {
    340             // The print service was uninstalled
    341             finishFragment();
    342         }
    343 
    344         mServiceEnabled = service.isEnabled();
    345 
    346         if (service.getSettingsActivityName() != null) {
    347             Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
    348 
    349             settingsIntent.setComponent(
    350                     new ComponentName(service.getComponentName().getPackageName(),
    351                             service.getSettingsActivityName()));
    352 
    353             List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities(
    354                     settingsIntent, 0);
    355             if (!resolvedActivities.isEmpty()) {
    356                 // The activity is a component name, therefore it is one or none.
    357                 if (resolvedActivities.get(0).activityInfo.exported) {
    358                     mSettingsIntent = settingsIntent;
    359                 }
    360             }
    361         } else {
    362             mSettingsIntent = null;
    363         }
    364 
    365         if (service.getAddPrintersActivityName() != null) {
    366             Intent addPrintersIntent = new Intent(Intent.ACTION_MAIN);
    367 
    368             addPrintersIntent.setComponent(
    369                     new ComponentName(service.getComponentName().getPackageName(),
    370                             service.getAddPrintersActivityName()));
    371 
    372             List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities(
    373                     addPrintersIntent, 0);
    374             if (!resolvedActivities.isEmpty()) {
    375                 // The activity is a component name, therefore it is one or none.
    376                 if (resolvedActivities.get(0).activityInfo.exported) {
    377                     mAddPrintersIntent = addPrintersIntent;
    378                 }
    379             }
    380         } else {
    381             mAddPrintersIntent = null;
    382         }
    383 
    384         updateUiForServiceState();
    385     }
    386 
    387     @Override
    388     public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
    389         updateUiForServiceState();
    390     }
    391 
    392     @Override
    393     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    394         super.onCreateOptionsMenu(menu, inflater);
    395         inflater.inflate(R.menu.print_service_settings, menu);
    396 
    397         MenuItem addPrinters = menu.findItem(R.id.print_menu_item_add_printer);
    398         if (mServiceEnabled && mAddPrintersIntent != null) {
    399             addPrinters.setIntent(mAddPrintersIntent);
    400         } else {
    401             menu.removeItem(R.id.print_menu_item_add_printer);
    402         }
    403 
    404         MenuItem settings = menu.findItem(R.id.print_menu_item_settings);
    405         if (mServiceEnabled && mSettingsIntent != null) {
    406             settings.setIntent(mSettingsIntent);
    407         } else {
    408             menu.removeItem(R.id.print_menu_item_settings);
    409         }
    410 
    411         MenuItem searchItem = menu.findItem(R.id.print_menu_item_search);
    412         if (mServiceEnabled && mPrintersAdapter.getUnfilteredCount() > 0) {
    413             mSearchView = (SearchView) searchItem.getActionView();
    414             mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    415                 @Override
    416                 public boolean onQueryTextSubmit(String query) {
    417                     return true;
    418                 }
    419 
    420                 @Override
    421                 public boolean onQueryTextChange(String searchString) {
    422                     mPrintersAdapter.getFilter().filter(searchString);
    423                     return true;
    424                 }
    425             });
    426             mSearchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
    427                 @Override
    428                 public void onViewAttachedToWindow(View view) {
    429                     if (AccessibilityManager.getInstance(getActivity()).isEnabled()) {
    430                         view.announceForAccessibility(getString(
    431                                 R.string.print_search_box_shown_utterance));
    432                     }
    433                 }
    434                 @Override
    435                 public void onViewDetachedFromWindow(View view) {
    436                     Activity activity = getActivity();
    437                     if (activity != null && !activity.isFinishing()
    438                             && AccessibilityManager.getInstance(activity).isEnabled()) {
    439                         view.announceForAccessibility(getString(
    440                                 R.string.print_search_box_hidden_utterance));
    441                     }
    442                 }
    443             });
    444         } else {
    445             menu.removeItem(R.id.print_menu_item_search);
    446         }
    447     }
    448 
    449     private final class PrintersAdapter extends BaseAdapter
    450             implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable {
    451         private final Object mLock = new Object();
    452 
    453         private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
    454 
    455         private final List<PrinterInfo> mFilteredPrinters = new ArrayList<PrinterInfo>();
    456 
    457         private CharSequence mLastSearchString;
    458 
    459         public void enable() {
    460             getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
    461         }
    462 
    463         public void disable() {
    464             getLoaderManager().destroyLoader(LOADER_ID_PRINTERS_LOADER);
    465             mPrinters.clear();
    466         }
    467 
    468         public int getUnfilteredCount() {
    469             return mPrinters.size();
    470         }
    471 
    472         @Override
    473         public Filter getFilter() {
    474             return new Filter() {
    475                 @Override
    476                 protected FilterResults performFiltering(CharSequence constraint) {
    477                     synchronized (mLock) {
    478                         if (TextUtils.isEmpty(constraint)) {
    479                             return null;
    480                         }
    481                         FilterResults results = new FilterResults();
    482                         List<PrinterInfo> filteredPrinters = new ArrayList<PrinterInfo>();
    483                         String constraintLowerCase = constraint.toString().toLowerCase();
    484                         final int printerCount = mPrinters.size();
    485                         for (int i = 0; i < printerCount; i++) {
    486                             PrinterInfo printer = mPrinters.get(i);
    487                             String name = printer.getName();
    488                             if (name != null && name.toLowerCase().contains(constraintLowerCase)) {
    489                                 filteredPrinters.add(printer);
    490                             }
    491                         }
    492                         results.values = filteredPrinters;
    493                         results.count = filteredPrinters.size();
    494                         return results;
    495                     }
    496                 }
    497 
    498                 @Override
    499                 @SuppressWarnings("unchecked")
    500                 protected void publishResults(CharSequence constraint, FilterResults results) {
    501                     synchronized (mLock) {
    502                         mLastSearchString = constraint;
    503                         mFilteredPrinters.clear();
    504                         if (results == null) {
    505                             mFilteredPrinters.addAll(mPrinters);
    506                         } else {
    507                             List<PrinterInfo> printers = (List<PrinterInfo>) results.values;
    508                             mFilteredPrinters.addAll(printers);
    509                         }
    510                     }
    511                     notifyDataSetChanged();
    512                 }
    513             };
    514         }
    515 
    516         @Override
    517         public int getCount() {
    518             synchronized (mLock) {
    519                 return mFilteredPrinters.size();
    520             }
    521         }
    522 
    523         @Override
    524         public Object getItem(int position) {
    525             synchronized (mLock) {
    526                 return mFilteredPrinters.get(position);
    527             }
    528         }
    529 
    530         @Override
    531         public long getItemId(int position) {
    532             return position;
    533         }
    534 
    535         /**
    536          * Checks if a printer can be used for printing
    537          *
    538          * @param position The position of the printer in the list
    539          * @return true iff the printer can be used for printing.
    540          */
    541         public boolean isActionable(int position) {
    542             PrinterInfo printer = (PrinterInfo) getItem(position);
    543             return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
    544         }
    545 
    546         @Override
    547         public View getView(int position, View convertView, ViewGroup parent) {
    548             if (convertView == null) {
    549                 convertView = getActivity().getLayoutInflater().inflate(
    550                         R.layout.printer_dropdown_item, parent, false);
    551             }
    552 
    553             convertView.setEnabled(isActionable(position));
    554 
    555             final PrinterInfo printer = (PrinterInfo) getItem(position);
    556             CharSequence title = printer.getName();
    557             CharSequence subtitle = printer.getDescription();
    558             Drawable icon = printer.loadIcon(getActivity());
    559 
    560             TextView titleView = (TextView) convertView.findViewById(R.id.title);
    561             titleView.setText(title);
    562 
    563             TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
    564             if (!TextUtils.isEmpty(subtitle)) {
    565                 subtitleView.setText(subtitle);
    566                 subtitleView.setVisibility(View.VISIBLE);
    567             } else {
    568                 subtitleView.setText(null);
    569                 subtitleView.setVisibility(View.GONE);
    570             }
    571 
    572             LinearLayout moreInfoView = (LinearLayout) convertView.findViewById(R.id.more_info);
    573             if (printer.getInfoIntent() != null) {
    574                 moreInfoView.setVisibility(View.VISIBLE);
    575                 moreInfoView.setOnClickListener(new OnClickListener() {
    576                     @Override
    577                     public void onClick(View v) {
    578                         try {
    579                             getActivity().startIntentSender(
    580                                     printer.getInfoIntent().getIntentSender(), null, 0, 0, 0);
    581                         } catch (SendIntentException e) {
    582                             Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
    583                         }
    584                     }
    585                 });
    586             } else {
    587                 moreInfoView.setVisibility(View.GONE);
    588             }
    589 
    590             ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
    591             if (icon != null) {
    592                 iconView.setVisibility(View.VISIBLE);
    593                 if (!isActionable(position)) {
    594                     icon.mutate();
    595 
    596                     TypedValue value = new TypedValue();
    597                     getActivity().getTheme().resolveAttribute(android.R.attr.disabledAlpha, value,
    598                             true);
    599                     icon.setAlpha((int)(value.getFloat() * 255));
    600                 }
    601                 iconView.setImageDrawable(icon);
    602             } else {
    603                 iconView.setVisibility(View.GONE);
    604             }
    605 
    606             return convertView;
    607         }
    608 
    609         @Override
    610         public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
    611             if (id == LOADER_ID_PRINTERS_LOADER) {
    612                 return new PrintersLoader(getContext());
    613             }
    614             return null;
    615         }
    616 
    617         @Override
    618         public void onLoadFinished(Loader<List<PrinterInfo>> loader,
    619                 List<PrinterInfo> printers) {
    620             synchronized (mLock) {
    621                 mPrinters.clear();
    622                 final int printerCount = printers.size();
    623                 for (int i = 0; i < printerCount; i++) {
    624                     PrinterInfo printer = printers.get(i);
    625                     if (printer.getId().getServiceName().equals(mComponentName)) {
    626                         mPrinters.add(printer);
    627                     }
    628                 }
    629                 mFilteredPrinters.clear();
    630                 mFilteredPrinters.addAll(mPrinters);
    631                 if (!TextUtils.isEmpty(mLastSearchString)) {
    632                     getFilter().filter(mLastSearchString);
    633                 }
    634             }
    635             notifyDataSetChanged();
    636         }
    637 
    638         @Override
    639         public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
    640             synchronized (mLock) {
    641                 mPrinters.clear();
    642                 mFilteredPrinters.clear();
    643                 mLastSearchString = null;
    644             }
    645             notifyDataSetInvalidated();
    646         }
    647     }
    648 
    649     private static class PrintersLoader extends Loader<List<PrinterInfo>> {
    650 
    651         private static final String LOG_TAG = "PrintersLoader";
    652 
    653         private static final boolean DEBUG = false;
    654 
    655         private final Map<PrinterId, PrinterInfo> mPrinters =
    656                 new LinkedHashMap<PrinterId, PrinterInfo>();
    657 
    658         private PrinterDiscoverySession mDiscoverySession;
    659 
    660         public PrintersLoader(Context context) {
    661             super(context);
    662         }
    663 
    664         @Override
    665         public void deliverResult(List<PrinterInfo> printers) {
    666             if (isStarted()) {
    667                 super.deliverResult(printers);
    668             }
    669         }
    670 
    671         @Override
    672         protected void onStartLoading() {
    673             if (DEBUG) {
    674                 Log.i(LOG_TAG, "onStartLoading()");
    675             }
    676             // The contract is that if we already have a valid,
    677             // result the we have to deliver it immediately.
    678             if (!mPrinters.isEmpty()) {
    679                 deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
    680             }
    681             // We want to start discovery at this point.
    682             onForceLoad();
    683         }
    684 
    685         @Override
    686         protected void onStopLoading() {
    687             if (DEBUG) {
    688                 Log.i(LOG_TAG, "onStopLoading()");
    689             }
    690             onCancelLoad();
    691         }
    692 
    693         @Override
    694         protected void onForceLoad() {
    695             if (DEBUG) {
    696                 Log.i(LOG_TAG, "onForceLoad()");
    697             }
    698             loadInternal();
    699         }
    700 
    701         @Override
    702         protected boolean onCancelLoad() {
    703             if (DEBUG) {
    704                 Log.i(LOG_TAG, "onCancelLoad()");
    705             }
    706             return cancelInternal();
    707         }
    708 
    709         @Override
    710         protected void onReset() {
    711             if (DEBUG) {
    712                 Log.i(LOG_TAG, "onReset()");
    713             }
    714             onStopLoading();
    715             mPrinters.clear();
    716             if (mDiscoverySession != null) {
    717                 mDiscoverySession.destroy();
    718                 mDiscoverySession = null;
    719             }
    720         }
    721 
    722         @Override
    723         protected void onAbandon() {
    724             if (DEBUG) {
    725                 Log.i(LOG_TAG, "onAbandon()");
    726             }
    727             onStopLoading();
    728         }
    729 
    730         private boolean cancelInternal() {
    731             if (mDiscoverySession != null
    732                     && mDiscoverySession.isPrinterDiscoveryStarted()) {
    733                 mDiscoverySession.stopPrinterDiscovery();
    734                 return true;
    735             }
    736             return false;
    737         }
    738 
    739         private void loadInternal() {
    740             if (mDiscoverySession == null) {
    741                 PrintManager printManager = (PrintManager) getContext()
    742                         .getSystemService(Context.PRINT_SERVICE);
    743                 mDiscoverySession = printManager.createPrinterDiscoverySession();
    744                 mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
    745                     @Override
    746                     public void onPrintersChanged() {
    747                         deliverResult(new ArrayList<PrinterInfo>(
    748                                 mDiscoverySession.getPrinters()));
    749                     }
    750                 });
    751             }
    752             mDiscoverySession.startPrinterDiscovery(null);
    753         }
    754     }
    755 }
    756