• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getMetricsCategory()127     public int getMetricsCategory() {
128         return MetricsEvent.PRINT_SERVICE_SETTINGS;
129     }
130 
131     @Override
onCreate(Bundle icicle)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
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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
onStart()152     public void onStart() {
153         super.onStart();
154         updateEmptyView();
155         updateUiForServiceState();
156     }
157 
158     @Override
onPause()159     public void onPause() {
160         if (mSearchView != null) {
161             mSearchView.setOnQueryTextListener(null);
162         }
163         super.onPause();
164     }
165 
166     @Override
onStop()167     public void onStop() {
168         super.onStop();
169     }
170 
171     @Override
onViewCreated(View view, Bundle savedInstanceState)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
onDestroyView()181     public void onDestroyView() {
182         super.onDestroyView();
183         mSwitchBar.removeOnSwitchChangeListener(this);
184         mSwitchBar.hide();
185     }
186 
onPreferenceToggled(String preferenceKey, boolean enabled)187     private void onPreferenceToggled(String preferenceKey, boolean enabled) {
188         ((PrintManager)getContext().getSystemService(Context.PRINT_SERVICE))
189                 .setPrintServiceEnabled(mComponentName, enabled);
190     }
191 
getBackupListView()192     private ListView getBackupListView() {
193         return (ListView) getView().findViewById(R.id.backup_list);
194     }
195 
updateEmptyView()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 
updateUiForServiceState()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 
initComponents()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
onSwitchChanged(Switch switchView, boolean isChecked)295     public void onSwitchChanged(Switch switchView, boolean isChecked) {
296         updateEmptyView();
297     }
298 
updateUiForArguments()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
onCreateLoader(int id, Bundle args)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
onLoadFinished(Loader<List<PrintServiceInfo>> loader, List<PrintServiceInfo> services)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
onLoaderReset(Loader<List<PrintServiceInfo>> loader)388     public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
389         updateUiForServiceState();
390     }
391 
392     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)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 
enable()459         public void enable() {
460             getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
461         }
462 
disable()463         public void disable() {
464             getLoaderManager().destroyLoader(LOADER_ID_PRINTERS_LOADER);
465             mPrinters.clear();
466         }
467 
getUnfilteredCount()468         public int getUnfilteredCount() {
469             return mPrinters.size();
470         }
471 
472         @Override
getFilter()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