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