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