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