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