blob: 42ef10e01158fea2dae266127cb33706668dca9d [file] [log] [blame]
Philip P. Moltmann66c96592016-02-24 11:32:43 -08001/*
2 * Copyright (C) 2016 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
17package com.android.printspooler.ui;
18
19import android.annotation.IntRange;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.app.ListActivity;
23import android.app.LoaderManager;
24import android.content.ActivityNotFoundException;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.Loader;
29import android.database.DataSetObserver;
30import android.net.Uri;
31import android.os.Bundle;
32import android.print.PrintManager;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070033import android.printservice.recommendation.RecommendationInfo;
34import android.print.PrintServiceRecommendationsLoader;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080035import android.print.PrintServicesLoader;
36import android.printservice.PrintServiceInfo;
37import android.provider.Settings;
38import android.text.TextUtils;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070039import android.util.ArraySet;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080040import android.util.Log;
41import android.util.Pair;
42import android.view.View;
43import android.view.ViewGroup;
44import android.widget.Adapter;
45import android.widget.AdapterView;
46import android.widget.BaseAdapter;
47import android.widget.ImageView;
48import android.widget.TextView;
49import com.android.printspooler.R;
50
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070051import java.text.Collator;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080052import java.util.ArrayList;
53import java.util.Collections;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070054import java.util.Comparator;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080055import java.util.List;
56
57/**
58 * This is an activity for adding a printer or. It consists of a list fed from three adapters:
59 * <ul>
60 * <li>{@link #mEnabledServicesAdapter} for all enabled services. If a service has an {@link
61 * PrintServiceInfo#getAddPrintersActivityName() add printer activity} this is started
62 * when the item is clicked.</li>
63 * <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page
64 * for this service is opened.</li>
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070065 * <li>{@link #mRecommendedServicesAdapter} for a link to all services. If this item is clicked
Philip P. Moltmann66c96592016-02-24 11:32:43 -080066 * the market app is opened to show all print services.</li>
67 * </ul>
68 */
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070069public class AddPrinterActivity extends ListActivity implements AdapterView.OnItemClickListener {
Philip P. Moltmann66c96592016-02-24 11:32:43 -080070 private static final String LOG_TAG = "AddPrinterActivity";
71
72 /** Ids for the loaders */
73 private static final int LOADER_ID_ENABLED_SERVICES = 1;
74 private static final int LOADER_ID_DISABLED_SERVICES = 2;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070075 private static final int LOADER_ID_RECOMMENDED_SERVICES = 3;
76 private static final int LOADER_ID_ALL_SERVICES = 4;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080077
78 /**
79 * The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES}
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070080 * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
Philip P. Moltmann66c96592016-02-24 11:32:43 -080081 */
82 private EnabledServicesAdapter mEnabledServicesAdapter;
83
84 /**
85 * The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES}
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070086 * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
Philip P. Moltmann66c96592016-02-24 11:32:43 -080087 */
88 private DisabledServicesAdapter mDisabledServicesAdapter;
89
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -070090 /**
91 * The recommended services list. This is filled from the
92 * {@link #LOADER_ID_RECOMMENDED_SERVICES} loader in
93 * {@link PrintServicePrintServiceRecommendationLoaderCallbacks#onLoadFinished}.
94 */
95 private RecommendedServicesAdapter mRecommendedServicesAdapter;
96
Philip P. Moltmann66c96592016-02-24 11:32:43 -080097 @Override
98 protected void onCreate(@Nullable Bundle savedInstanceState) {
99 super.onCreate(savedInstanceState);
100
101 setContentView(R.layout.add_printer_activity);
102
103 mEnabledServicesAdapter = new EnabledServicesAdapter();
104 mDisabledServicesAdapter = new DisabledServicesAdapter();
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700105 mRecommendedServicesAdapter = new RecommendedServicesAdapter();
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800106
107 ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
108 adapterList.add(mEnabledServicesAdapter);
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700109 adapterList.add(mRecommendedServicesAdapter);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800110 adapterList.add(mDisabledServicesAdapter);
111
112 setListAdapter(new CombinedAdapter(adapterList));
113
114 getListView().setOnItemClickListener(this);
115
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700116 PrintServiceInfoLoaderCallbacks printServiceLoaderCallbacks =
117 new PrintServiceInfoLoaderCallbacks();
118
119 getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
120 getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
121 getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
122 new PrintServicePrintServiceRecommendationLoaderCallbacks());
123 getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800124 }
125
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700126 /**
127 * Callbacks for the loaders operating on list of {@link PrintServiceInfo print service infos}.
128 */
129 private class PrintServiceInfoLoaderCallbacks implements
130 LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
131 @Override
132 public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
133 switch (id) {
134 case LOADER_ID_ENABLED_SERVICES:
135 return new PrintServicesLoader(
136 (PrintManager) getSystemService(Context.PRINT_SERVICE),
137 AddPrinterActivity.this, PrintManager.ENABLED_SERVICES);
138 case LOADER_ID_DISABLED_SERVICES:
139 return new PrintServicesLoader(
140 (PrintManager) getSystemService(Context.PRINT_SERVICE),
141 AddPrinterActivity.this, PrintManager.DISABLED_SERVICES);
142 case LOADER_ID_ALL_SERVICES:
143 return new PrintServicesLoader(
144 (PrintManager) getSystemService(Context.PRINT_SERVICE),
145 AddPrinterActivity.this, PrintManager.ALL_SERVICES);
146 default:
147 // not reached
148 return null;
149 }
150 }
151
152
153 @Override
154 public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
155 List<PrintServiceInfo> data) {
156 switch (loader.getId()) {
157 case LOADER_ID_ENABLED_SERVICES:
158 mEnabledServicesAdapter.updateData(data);
159 break;
160 case LOADER_ID_DISABLED_SERVICES:
161 mDisabledServicesAdapter.updateData(data);
162 break;
163 case LOADER_ID_ALL_SERVICES:
164 mRecommendedServicesAdapter.updateInstalledServices(data);
165 default:
166 // not reached
167 }
168 }
169
170 @Override
171 public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
172 if (!isFinishing()) {
173 switch (loader.getId()) {
174 case LOADER_ID_ENABLED_SERVICES:
175 mEnabledServicesAdapter.updateData(null);
176 break;
177 case LOADER_ID_DISABLED_SERVICES:
178 mDisabledServicesAdapter.updateData(null);
179 break;
180 case LOADER_ID_ALL_SERVICES:
181 mRecommendedServicesAdapter.updateInstalledServices(null);
182 break;
183 default:
184 // not reached
185 }
186 }
187 }
188 }
189
190 /**
191 * Callbacks for the loaders operating on list of {@link RecommendationInfo print service
192 * recommendations}.
193 */
194 private class PrintServicePrintServiceRecommendationLoaderCallbacks implements
195 LoaderManager.LoaderCallbacks<List<RecommendationInfo>> {
196 @Override
197 public Loader<List<RecommendationInfo>> onCreateLoader(int id, Bundle args) {
198 return new PrintServiceRecommendationsLoader(
199 (PrintManager) getSystemService(Context.PRINT_SERVICE),
200 AddPrinterActivity.this);
201 }
202
203
204 @Override
205 public void onLoadFinished(Loader<List<RecommendationInfo>> loader,
206 List<RecommendationInfo> data) {
207 mRecommendedServicesAdapter.updateRecommendations(data);
208 }
209
210 @Override
211 public void onLoaderReset(Loader<List<RecommendationInfo>> loader) {
212 if (!isFinishing()) {
213 mRecommendedServicesAdapter.updateRecommendations(null);
214 }
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800215 }
216 }
217
218 @Override
219 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
220 ((ActionAdapter) getListAdapter()).performAction(position);
221 }
222
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800223 /**
224 * Marks an adapter that can can perform an action for a position in it's list.
225 */
226 private abstract class ActionAdapter extends BaseAdapter {
227 /**
228 * Perform the action for a position in the list.
229 *
230 * @param position The position of the item
231 */
232 abstract void performAction(@IntRange(from = 0) int position);
233
234 @Override
235 public boolean areAllItemsEnabled() {
236 return false;
237 }
238 }
239
240 /**
241 * An adapter presenting multiple sub adapters as a single combined adapter.
242 */
243 private class CombinedAdapter extends ActionAdapter {
244 /** The adapters to combine */
245 private final @NonNull ArrayList<ActionAdapter> mAdapters;
246
247 /**
248 * Create a combined adapter.
249 *
250 * @param adapters the list of adapters to combine
251 */
252 CombinedAdapter(@NonNull ArrayList<ActionAdapter> adapters) {
253 mAdapters = adapters;
254
255 final int numAdapters = mAdapters.size();
256 for (int i = 0; i < numAdapters; i++) {
257 mAdapters.get(i).registerDataSetObserver(new DataSetObserver() {
258 @Override
259 public void onChanged() {
260 notifyDataSetChanged();
261 }
262
263 @Override
264 public void onInvalidated() {
265 notifyDataSetChanged();
266 }
267 });
268 }
269 }
270
271 @Override
272 public int getCount() {
273 int totalCount = 0;
274
275 final int numAdapters = mAdapters.size();
276 for (int i = 0; i < numAdapters; i++) {
277 totalCount += mAdapters.get(i).getCount();
278 }
279
280 return totalCount;
281 }
282
283 /**
284 * Find the sub adapter and the position in the sub-adapter the position in the combined
285 * adapter refers to.
286 *
287 * @param position The position in the combined adapter
288 *
289 * @return The pair of adapter and position in sub adapter
290 */
291 private @NonNull Pair<ActionAdapter, Integer> getSubAdapter(int position) {
292 final int numAdapters = mAdapters.size();
293 for (int i = 0; i < numAdapters; i++) {
294 ActionAdapter adapter = mAdapters.get(i);
295
296 if (position < adapter.getCount()) {
297 return new Pair<>(adapter, position);
298 } else {
299 position -= adapter.getCount();
300 }
301 }
302
303 throw new IllegalArgumentException("Invalid position");
304 }
305
306 @Override
307 public int getItemViewType(int position) {
308 int numLowerViewTypes = 0;
309
310 final int numAdapters = mAdapters.size();
311 for (int i = 0; i < numAdapters; i++) {
312 Adapter adapter = mAdapters.get(i);
313
314 if (position < adapter.getCount()) {
315 return numLowerViewTypes + adapter.getItemViewType(position);
316 } else {
317 numLowerViewTypes += adapter.getViewTypeCount();
318 position -= adapter.getCount();
319 }
320 }
321
322 throw new IllegalArgumentException("Invalid position");
323 }
324
325 @Override
326 public int getViewTypeCount() {
327 int totalViewCount = 0;
328
329 final int numAdapters = mAdapters.size();
330 for (int i = 0; i < numAdapters; i++) {
331 totalViewCount += mAdapters.get(i).getViewTypeCount();
332 }
333
334 return totalViewCount;
335 }
336
337 @Override
338 public View getView(int position, View convertView, ViewGroup parent) {
339 Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
340
341 return realPosition.first.getView(realPosition.second, convertView, parent);
342 }
343
344 @Override
345 public Object getItem(int position) {
346 Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
347
348 return realPosition.first.getItem(realPosition.second);
349 }
350
351 @Override
352 public long getItemId(int position) {
353 return position;
354 }
355
356 @Override
357 public boolean isEnabled(int position) {
358 Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
359
360 return realPosition.first.isEnabled(realPosition.second);
361 }
362
363 @Override
364 public void performAction(@IntRange(from = 0) int position) {
365 Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
366
367 realPosition.first.performAction(realPosition.second);
368 }
369 }
370
371 /**
372 * Superclass for all adapters that just display a list of {@link PrintServiceInfo}.
373 */
374 private abstract class PrintServiceInfoAdapter extends ActionAdapter {
375 /**
376 * Raw data of the list.
377 *
378 * @see #updateData(List)
379 */
380 private @NonNull List<PrintServiceInfo> mServices;
381
382 /**
383 * Create a new adapter.
384 */
385 PrintServiceInfoAdapter() {
386 mServices = Collections.emptyList();
387 }
388
389 /**
390 * Update the data.
391 *
392 * @param services The new raw data.
393 */
394 void updateData(@Nullable List<PrintServiceInfo> services) {
395 if (services == null || services.isEmpty()) {
396 mServices = Collections.emptyList();
397 } else {
398 mServices = services;
399 }
400
401 notifyDataSetChanged();
402 }
403
404 @Override
405 public int getViewTypeCount() {
406 return 2;
407 }
408
409 @Override
410 public int getItemViewType(int position) {
411 if (position == 0) {
412 return 0;
413 } else {
414 return 1;
415 }
416 }
417
418 @Override
419 public int getCount() {
420 if (mServices.isEmpty()) {
421 return 0;
422 } else {
423 return mServices.size() + 1;
424 }
425 }
426
427 @Override
428 public Object getItem(int position) {
429 if (position == 0) {
430 return null;
431 } else {
432 return mServices.get(position - 1);
433 }
434 }
435
436 @Override
437 public boolean isEnabled(int position) {
438 return position != 0;
439 }
440
441 @Override
442 public long getItemId(int position) {
443 return position;
444 }
445 }
446
447 /**
448 * Adapter for the enabled services.
449 */
450 private class EnabledServicesAdapter extends PrintServiceInfoAdapter {
451 @Override
452 public void performAction(@IntRange(from = 0) int position) {
453 PrintServiceInfo service = (PrintServiceInfo) getItem(position);
454 String addPrinterActivityName = service.getAddPrintersActivityName();
455
456 if (!TextUtils.isEmpty(addPrinterActivityName)) {
457 Intent intent = new Intent(Intent.ACTION_MAIN);
458 intent.setComponent(new ComponentName(service.getComponentName().getPackageName(),
459 addPrinterActivityName));
460
461 try {
462 startActivity(intent);
463 } catch (ActivityNotFoundException e) {
464 Log.e(LOG_TAG, "Cannot start add printers activity", e);
465 }
466 }
467 }
468
469 @Override
470 public View getView(int position, View convertView, ViewGroup parent) {
471 if (position == 0) {
472 if (convertView == null) {
473 convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
474 parent, false);
475 }
476
477 ((TextView) convertView.findViewById(R.id.text))
478 .setText(R.string.enabled_services_title);
479
480 return convertView;
481 }
482
483 if (convertView == null) {
484 convertView = getLayoutInflater().inflate(R.layout.enabled_print_services_list_item,
485 parent, false);
486 }
487
488 PrintServiceInfo service = (PrintServiceInfo) getItem(position);
489
490 TextView title = (TextView) convertView.findViewById(R.id.title);
491 ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
492 TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle);
493
494 title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
495 icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
496
497 if (TextUtils.isEmpty(service.getAddPrintersActivityName())) {
498 subtitle.setText(getString(R.string.cannot_add_printer));
499 } else {
500 subtitle.setText(getString(R.string.select_to_add_printers));
501 }
502
503 return convertView;
504 }
505 }
506
507 /**
508 * Adapter for the disabled services.
509 */
510 private class DisabledServicesAdapter extends PrintServiceInfoAdapter {
511 @Override
512 public void performAction(@IntRange(from = 0) int position) {
513 ((PrintManager) getSystemService(Context.PRINT_SERVICE)).setPrintServiceEnabled(
514 ((PrintServiceInfo) getItem(position)).getComponentName(), true);
515 }
516
517 @Override
518 public View getView(int position, View convertView, ViewGroup parent) {
519 if (position == 0) {
520 if (convertView == null) {
521 convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
522 parent, false);
523 }
524
525 ((TextView) convertView.findViewById(R.id.text))
526 .setText(R.string.disabled_services_title);
527
528 return convertView;
529 }
530
531 if (convertView == null) {
532 convertView = getLayoutInflater().inflate(
533 R.layout.disabled_print_services_list_item, parent, false);
534 }
535
536 PrintServiceInfo service = (PrintServiceInfo) getItem(position);
537
538 TextView title = (TextView) convertView.findViewById(R.id.title);
539 ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
540
541 title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
542 icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
543
544 return convertView;
545 }
546 }
547
548 /**
549 * Adapter for the recommended services.
550 */
551 private class RecommendedServicesAdapter extends ActionAdapter {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700552 /** Package names of all installed print services */
553 private @NonNull final ArraySet<String> mInstalledServices;
554
555 /** All print service recommendations */
556 private @Nullable List<RecommendationInfo> mRecommendations;
557
558 /**
559 * Sorted print service recommendations for services that are not installed
560 *
561 * @see #filterRecommendations
562 */
563 private @Nullable List<RecommendationInfo> mFilteredRecommendations;
564
565 /**
566 * Create a new adapter.
567 */
568 private RecommendedServicesAdapter() {
569 mInstalledServices = new ArraySet<>();
570 }
571
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800572 @Override
573 public int getCount() {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700574 if (mFilteredRecommendations == null) {
575 return 2;
576 } else {
577 return mFilteredRecommendations.size() + 2;
578 }
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800579 }
580
581 @Override
582 public int getViewTypeCount() {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700583 return 3;
584 }
585
586 /**
587 * @return The position the all services link is at.
588 */
589 private int getAllServicesPos() {
590 return getCount() - 1;
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800591 }
592
593 @Override
594 public int getItemViewType(int position) {
595 if (position == 0) {
596 return 0;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700597 } else if (getAllServicesPos() == position) {
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800598 return 1;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700599 } else {
600 return 2;
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800601 }
602 }
603
604 @Override
605 public Object getItem(int position) {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700606 if (position == 0 || position == getAllServicesPos()) {
607 return null;
608 } else {
609 return mFilteredRecommendations.get(position - 1);
610 }
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800611 }
612
613 @Override
614 public long getItemId(int position) {
615 return position;
616 }
617
618 @Override
619 public View getView(int position, View convertView, ViewGroup parent) {
620 if (position == 0) {
621 if (convertView == null) {
622 convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
623 parent, false);
624 }
625
626 ((TextView) convertView.findViewById(R.id.text))
627 .setText(R.string.recommended_services_title);
628
629 return convertView;
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700630 } else if (position == getAllServicesPos()) {
631 if (convertView == null) {
632 convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
633 parent, false);
634 }
635 } else {
636 RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800637
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700638 if (convertView == null) {
639 convertView = getLayoutInflater().inflate(
640 R.layout.print_service_recommendations_list_item, parent, false);
641 }
642
643 ((TextView) convertView.findViewById(R.id.title)).setText(recommendation.getName());
644
645 ((TextView) convertView.findViewById(R.id.subtitle)).setText(getResources()
646 .getQuantityString(R.plurals.print_services_recommendation_subtitle,
647 recommendation.getNumDiscoveredPrinters(),
648 recommendation.getNumDiscoveredPrinters()));
649
650 return convertView;
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800651 }
652
653 return convertView;
654 }
655
656 @Override
657 public boolean isEnabled(int position) {
658 return position != 0;
659 }
660
661 @Override
662 public void performAction(@IntRange(from = 0) int position) {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700663 if (position == getAllServicesPos()) {
664 String searchUri = Settings.Secure
665 .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800666
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700667 if (searchUri != null) {
668 try {
669 startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
670 } catch (ActivityNotFoundException e) {
671 Log.e(LOG_TAG, "Cannot start market", e);
672 }
673 }
674 } else {
675 RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
676
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800677 try {
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700678 startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(
679 R.string.uri_package_details, recommendation.getPackageName()))));
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800680 } catch (ActivityNotFoundException e) {
681 Log.e(LOG_TAG, "Cannot start market", e);
682 }
683 }
684 }
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -0700685
686 /**
687 * Filter recommended services.
688 */
689 private void filterRecommendations() {
690 if (mRecommendations == null) {
691 mFilteredRecommendations = null;
692 } else {
693 mFilteredRecommendations = new ArrayList<>();
694
695 // Filter out recommendations for already installed services
696 final int numRecommendations = mRecommendations.size();
697 for (int i = 0; i < numRecommendations; i++) {
698 RecommendationInfo recommendation = mRecommendations.get(i);
699
700 if (!mInstalledServices.contains(recommendation.getPackageName())) {
701 mFilteredRecommendations.add(recommendation);
702 }
703 }
704 }
705
706 notifyDataSetChanged();
707 }
708
709 /**
710 * Update the installed print services.
711 *
712 * @param services The new set of services
713 */
714 public void updateInstalledServices(List<PrintServiceInfo> services) {
715 mInstalledServices.clear();
716
717 final int numServices = services.size();
718 for (int i = 0; i < numServices; i++) {
719 mInstalledServices.add(services.get(i).getComponentName().getPackageName());
720 }
721
722 filterRecommendations();
723 }
724
725 /**
726 * Update the recommended print services.
727 *
728 * @param recommendations The new set of recommendations
729 */
730 public void updateRecommendations(List<RecommendationInfo> recommendations) {
731 if (recommendations != null) {
732 final Collator collator = Collator.getInstance();
733
734 // Sort recommendations (early conditions are more important)
735 // - higher number of discovered printers first
736 // - single vendor services first
737 // - alphabetically
738 Collections.sort(recommendations,
739 new Comparator<RecommendationInfo>() {
740 @Override public int compare(RecommendationInfo o1,
741 RecommendationInfo o2) {
742 if (o1.getNumDiscoveredPrinters() !=
743 o2.getNumDiscoveredPrinters()) {
744 return o2.getNumDiscoveredPrinters() -
745 o1.getNumDiscoveredPrinters();
746 } else if (o1.recommendsMultiVendorService()
747 != o2.recommendsMultiVendorService()) {
748 if (o1.recommendsMultiVendorService()) {
749 return 1;
750 } else {
751 return -1;
752 }
753 } else {
754 return collator.compare(o1.getName().toString(),
755 o2.getName().toString());
756 }
757 }
758 });
759 }
760
761 mRecommendations = recommendations;
762
763 filterRecommendations();
764 }
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800765 }
766}